Commit 39604478 authored by Kunshan Wang's avatar Kunshan Wang

Added status flags (NZCV) to binOp.

In the text form, the NZCV flags are optional, so existing programs
are still valid. In the bundle building API, `new_binop` remain
unchanged, but an additional function `new_binop_with_status` is added,
so existing programs are still valid.

scripts/*.py are modified to adapt the MuBinOpStatus enum type.
parent 58d95aec
......@@ -607,42 +607,43 @@ The canonical definition of each function is in the `IR Builder API
[0x328]@uvm.irbuilder.new_nsc_pass_values (%b: irbuilderref, %id: int<32>, %tys: iref<int<32>>, %vars: iref<int<32>>, %ntysvars: int<64>) -> ()
[0x329]@uvm.irbuilder.new_nsc_throw_exc (%b: irbuilderref, %id: int<32>, %exc: int<32>) -> ()
[0x32a]@uvm.irbuilder.new_binop (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %optr: int<32>, %ty: int<32>, %opnd1: int<32>, %opnd2: int<32>, %exc_clause: int<32>) -> ()
[0x32b]@uvm.irbuilder.new_cmp (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %optr: int<32>, %ty: int<32>, %opnd1: int<32>, %opnd2: int<32>) -> ()
[0x32c]@uvm.irbuilder.new_conv (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %optr: int<32>, %from_ty: int<32>, %to_ty: int<32>, %opnd: int<32>) -> ()
[0x32d]@uvm.irbuilder.new_select (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %cond_ty: int<32>, %opnd_ty: int<32>, %cond: int<32>, %if_true: int<32>, %if_false: int<32>) -> ()
[0x32e]@uvm.irbuilder.new_branch (%b: irbuilderref, %id: int<32>, %dest: int<32>) -> ()
[0x32f]@uvm.irbuilder.new_branch2 (%b: irbuilderref, %id: int<32>, %cond: int<32>, %if_true: int<32>, %if_false: int<32>) -> ()
[0x330]@uvm.irbuilder.new_switch (%b: irbuilderref, %id: int<32>, %opnd_ty: int<32>, %opnd: int<32>, %default_dest: int<32>, %cases: iref<int<32>>, %dests: iref<int<32>>, %ncasesdests: int<64>) -> ()
[0x331]@uvm.irbuilder.new_call (%b: irbuilderref, %id: int<32>, %result_ids: iref<int<32>>, %n_result_ids: int<64>, %sig: int<32>, %callee: int<32>, %args: iref<int<32>>, %nargs: int<64>, %exc_clause: int<32>, %keepalive_clause: int<32>) -> ()
[0x332]@uvm.irbuilder.new_tailcall (%b: irbuilderref, %id: int<32>, %sig: int<32>, %callee: int<32>, %args: iref<int<32>>, %nargs: int<64>) -> ()
[0x333]@uvm.irbuilder.new_ret (%b: irbuilderref, %id: int<32>, %rvs: iref<int<32>>, %nrvs: int<64>) -> ()
[0x334]@uvm.irbuilder.new_throw (%b: irbuilderref, %id: int<32>, %exc: int<32>) -> ()
[0x335]@uvm.irbuilder.new_extractvalue (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %strty: int<32>, %index: int<32>, %opnd: int<32>) -> ()
[0x336]@uvm.irbuilder.new_insertvalue (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %strty: int<32>, %index: int<32>, %opnd: int<32>, %newval: int<32>) -> ()
[0x337]@uvm.irbuilder.new_extractelement (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %seqty: int<32>, %indty: int<32>, %opnd: int<32>, %index: int<32>) -> ()
[0x338]@uvm.irbuilder.new_insertelement (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %seqty: int<32>, %indty: int<32>, %opnd: int<32>, %index: int<32>, %newval: int<32>) -> ()
[0x339]@uvm.irbuilder.new_shufflevector (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %vecty: int<32>, %maskty: int<32>, %vec1: int<32>, %vec2: int<32>, %mask: int<32>) -> ()
[0x33a]@uvm.irbuilder.new_new (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %allocty: int<32>, %exc_clause: int<32>) -> ()
[0x33b]@uvm.irbuilder.new_newhybrid (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %allocty: int<32>, %lenty: int<32>, %length: int<32>, %exc_clause: int<32>) -> ()
[0x33c]@uvm.irbuilder.new_alloca (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %allocty: int<32>, %exc_clause: int<32>) -> ()
[0x33d]@uvm.irbuilder.new_allocahybrid (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %allocty: int<32>, %lenty: int<32>, %length: int<32>, %exc_clause: int<32>) -> ()
[0x33e]@uvm.irbuilder.new_getiref (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %refty: int<32>, %opnd: int<32>) -> ()
[0x33f]@uvm.irbuilder.new_getfieldiref (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %is_ptr: int<32>, %refty: int<32>, %index: int<32>, %opnd: int<32>) -> ()
[0x340]@uvm.irbuilder.new_getelemiref (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %is_ptr: int<32>, %refty: int<32>, %indty: int<32>, %opnd: int<32>, %index: int<32>) -> ()
[0x341]@uvm.irbuilder.new_shiftiref (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %is_ptr: int<32>, %refty: int<32>, %offty: int<32>, %opnd: int<32>, %offset: int<32>) -> ()
[0x342]@uvm.irbuilder.new_getvarpartiref (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %is_ptr: int<32>, %refty: int<32>, %opnd: int<32>) -> ()
[0x343]@uvm.irbuilder.new_load (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %is_ptr: int<32>, %ord: int<32>, %refty: int<32>, %loc: int<32>, %exc_clause: int<32>) -> ()
[0x344]@uvm.irbuilder.new_store (%b: irbuilderref, %id: int<32>, %is_ptr: int<32>, %ord: int<32>, %refty: int<32>, %loc: int<32>, %newval: int<32>, %exc_clause: int<32>) -> ()
[0x345]@uvm.irbuilder.new_cmpxchg (%b: irbuilderref, %id: int<32>, %value_result_id: int<32>, %succ_result_id: int<32>, %is_ptr: int<32>, %is_weak: int<32>, %ord_succ: int<32>, %ord_fail: int<32>, %refty: int<32>, %loc: int<32>, %expected: int<32>, %desired: int<32>, %exc_clause: int<32>) -> ()
[0x346]@uvm.irbuilder.new_atomicrmw (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %is_ptr: int<32>, %ord: int<32>, %optr: int<32>, %refTy: int<32>, %loc: int<32>, %opnd: int<32>, %exc_clause: int<32>) -> ()
[0x347]@uvm.irbuilder.new_fence (%b: irbuilderref, %id: int<32>, %ord: int<32>) -> ()
[0x348]@uvm.irbuilder.new_trap (%b: irbuilderref, %id: int<32>, %result_ids: iref<int<32>>, %rettys: iref<int<32>>, %nretvals: int<64>, %exc_clause: int<32>, %keepalive_clause: int<32>) -> ()
[0x349]@uvm.irbuilder.new_watchpoint (%b: irbuilderref, %id: int<32>, %wpid: int<32>, %result_ids: iref<int<32>>, %rettys: iref<int<32>>, %nretvals: int<64>, %dis: int<32>, %ena: int<32>, %exc: int<32>, %keepalive_clause: int<32>) -> ()
[0x34a]@uvm.irbuilder.new_wpbranch (%b: irbuilderref, %id: int<32>, %wpid: int<32>, %dis: int<32>, %ena: int<32>) -> ()
[0x34b]@uvm.irbuilder.new_ccall (%b: irbuilderref, %id: int<32>, %result_ids: iref<int<32>>, %n_result_ids: int<64>, %callconv: int<32>, %callee_ty: int<32>, %sig: int<32>, %callee: int<32>, %args: iref<int<32>>, %nargs: int<64>, %exc_clause: int<32>, %keepalive_clause: int<32>) -> ()
[0x34c]@uvm.irbuilder.new_newthread (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %stack: int<32>, %threadlocal: int<32>, %new_stack_clause: int<32>, %exc_clause: int<32>) -> ()
[0x34d]@uvm.irbuilder.new_swapstack (%b: irbuilderref, %id: int<32>, %result_ids: iref<int<32>>, %n_result_ids: int<64>, %swappee: int<32>, %cur_stack_clause: int<32>, %new_stack_clause: int<32>, %exc_clause: int<32>, %keepalive_clause: int<32>) -> ()
[0x34e]@uvm.irbuilder.new_comminst (%b: irbuilderref, %id: int<32>, %result_ids: iref<int<32>>, %n_result_ids: int<64>, %opcode: int<32>, %flags: iref<int<32>>, %nflags: int<64>, %tys: iref<int<32>>, %ntys: int<64>, %sigs: iref<int<32>>, %nsigs: int<64>, %args: iref<int<32>>, %nargs: int<64>, %exc_clause: int<32>, %keepalive_clause: int<32>) -> ()
[0x32b]@uvm.irbuilder.new_binop_with_status (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %status_result_ids: iref<int<32>>, %n_status_result_ids: int<64>, %status_flags: int<32>, %optr: int<32>, %ty: int<32>, %opnd1: int<32>, %opnd2: int<32>, %exc_clause: int<32>) -> ()
[0x32c]@uvm.irbuilder.new_cmp (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %optr: int<32>, %ty: int<32>, %opnd1: int<32>, %opnd2: int<32>) -> ()
[0x32d]@uvm.irbuilder.new_conv (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %optr: int<32>, %from_ty: int<32>, %to_ty: int<32>, %opnd: int<32>) -> ()
[0x32e]@uvm.irbuilder.new_select (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %cond_ty: int<32>, %opnd_ty: int<32>, %cond: int<32>, %if_true: int<32>, %if_false: int<32>) -> ()
[0x32f]@uvm.irbuilder.new_branch (%b: irbuilderref, %id: int<32>, %dest: int<32>) -> ()
[0x330]@uvm.irbuilder.new_branch2 (%b: irbuilderref, %id: int<32>, %cond: int<32>, %if_true: int<32>, %if_false: int<32>) -> ()
[0x331]@uvm.irbuilder.new_switch (%b: irbuilderref, %id: int<32>, %opnd_ty: int<32>, %opnd: int<32>, %default_dest: int<32>, %cases: iref<int<32>>, %dests: iref<int<32>>, %ncasesdests: int<64>) -> ()
[0x332]@uvm.irbuilder.new_call (%b: irbuilderref, %id: int<32>, %result_ids: iref<int<32>>, %n_result_ids: int<64>, %sig: int<32>, %callee: int<32>, %args: iref<int<32>>, %nargs: int<64>, %exc_clause: int<32>, %keepalive_clause: int<32>) -> ()
[0x333]@uvm.irbuilder.new_tailcall (%b: irbuilderref, %id: int<32>, %sig: int<32>, %callee: int<32>, %args: iref<int<32>>, %nargs: int<64>) -> ()
[0x334]@uvm.irbuilder.new_ret (%b: irbuilderref, %id: int<32>, %rvs: iref<int<32>>, %nrvs: int<64>) -> ()
[0x335]@uvm.irbuilder.new_throw (%b: irbuilderref, %id: int<32>, %exc: int<32>) -> ()
[0x336]@uvm.irbuilder.new_extractvalue (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %strty: int<32>, %index: int<32>, %opnd: int<32>) -> ()
[0x337]@uvm.irbuilder.new_insertvalue (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %strty: int<32>, %index: int<32>, %opnd: int<32>, %newval: int<32>) -> ()
[0x338]@uvm.irbuilder.new_extractelement (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %seqty: int<32>, %indty: int<32>, %opnd: int<32>, %index: int<32>) -> ()
[0x339]@uvm.irbuilder.new_insertelement (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %seqty: int<32>, %indty: int<32>, %opnd: int<32>, %index: int<32>, %newval: int<32>) -> ()
[0x33a]@uvm.irbuilder.new_shufflevector (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %vecty: int<32>, %maskty: int<32>, %vec1: int<32>, %vec2: int<32>, %mask: int<32>) -> ()
[0x33b]@uvm.irbuilder.new_new (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %allocty: int<32>, %exc_clause: int<32>) -> ()
[0x33c]@uvm.irbuilder.new_newhybrid (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %allocty: int<32>, %lenty: int<32>, %length: int<32>, %exc_clause: int<32>) -> ()
[0x33d]@uvm.irbuilder.new_alloca (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %allocty: int<32>, %exc_clause: int<32>) -> ()
[0x33e]@uvm.irbuilder.new_allocahybrid (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %allocty: int<32>, %lenty: int<32>, %length: int<32>, %exc_clause: int<32>) -> ()
[0x33f]@uvm.irbuilder.new_getiref (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %refty: int<32>, %opnd: int<32>) -> ()
[0x340]@uvm.irbuilder.new_getfieldiref (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %is_ptr: int<32>, %refty: int<32>, %index: int<32>, %opnd: int<32>) -> ()
[0x341]@uvm.irbuilder.new_getelemiref (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %is_ptr: int<32>, %refty: int<32>, %indty: int<32>, %opnd: int<32>, %index: int<32>) -> ()
[0x342]@uvm.irbuilder.new_shiftiref (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %is_ptr: int<32>, %refty: int<32>, %offty: int<32>, %opnd: int<32>, %offset: int<32>) -> ()
[0x343]@uvm.irbuilder.new_getvarpartiref (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %is_ptr: int<32>, %refty: int<32>, %opnd: int<32>) -> ()
[0x344]@uvm.irbuilder.new_load (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %is_ptr: int<32>, %ord: int<32>, %refty: int<32>, %loc: int<32>, %exc_clause: int<32>) -> ()
[0x345]@uvm.irbuilder.new_store (%b: irbuilderref, %id: int<32>, %is_ptr: int<32>, %ord: int<32>, %refty: int<32>, %loc: int<32>, %newval: int<32>, %exc_clause: int<32>) -> ()
[0x346]@uvm.irbuilder.new_cmpxchg (%b: irbuilderref, %id: int<32>, %value_result_id: int<32>, %succ_result_id: int<32>, %is_ptr: int<32>, %is_weak: int<32>, %ord_succ: int<32>, %ord_fail: int<32>, %refty: int<32>, %loc: int<32>, %expected: int<32>, %desired: int<32>, %exc_clause: int<32>) -> ()
[0x347]@uvm.irbuilder.new_atomicrmw (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %is_ptr: int<32>, %ord: int<32>, %optr: int<32>, %refTy: int<32>, %loc: int<32>, %opnd: int<32>, %exc_clause: int<32>) -> ()
[0x348]@uvm.irbuilder.new_fence (%b: irbuilderref, %id: int<32>, %ord: int<32>) -> ()
[0x349]@uvm.irbuilder.new_trap (%b: irbuilderref, %id: int<32>, %result_ids: iref<int<32>>, %rettys: iref<int<32>>, %nretvals: int<64>, %exc_clause: int<32>, %keepalive_clause: int<32>) -> ()
[0x34a]@uvm.irbuilder.new_watchpoint (%b: irbuilderref, %id: int<32>, %wpid: int<32>, %result_ids: iref<int<32>>, %rettys: iref<int<32>>, %nretvals: int<64>, %dis: int<32>, %ena: int<32>, %exc: int<32>, %keepalive_clause: int<32>) -> ()
[0x34b]@uvm.irbuilder.new_wpbranch (%b: irbuilderref, %id: int<32>, %wpid: int<32>, %dis: int<32>, %ena: int<32>) -> ()
[0x34c]@uvm.irbuilder.new_ccall (%b: irbuilderref, %id: int<32>, %result_ids: iref<int<32>>, %n_result_ids: int<64>, %callconv: int<32>, %callee_ty: int<32>, %sig: int<32>, %callee: int<32>, %args: iref<int<32>>, %nargs: int<64>, %exc_clause: int<32>, %keepalive_clause: int<32>) -> ()
[0x34d]@uvm.irbuilder.new_newthread (%b: irbuilderref, %id: int<32>, %result_id: int<32>, %stack: int<32>, %threadlocal: int<32>, %new_stack_clause: int<32>, %exc_clause: int<32>) -> ()
[0x34e]@uvm.irbuilder.new_swapstack (%b: irbuilderref, %id: int<32>, %result_ids: iref<int<32>>, %n_result_ids: int<64>, %swappee: int<32>, %cur_stack_clause: int<32>, %new_stack_clause: int<32>, %exc_clause: int<32>, %keepalive_clause: int<32>) -> ()
[0x34f]@uvm.irbuilder.new_comminst (%b: irbuilderref, %id: int<32>, %result_ids: iref<int<32>>, %n_result_ids: int<64>, %opcode: int<32>, %flags: iref<int<32>>, %nflags: int<64>, %tys: iref<int<32>>, %ntys: int<64>, %sigs: iref<int<32>>, %nsigs: int<64>, %args: iref<int<32>>, %nargs: int<64>, %exc_clause: int<32>, %keepalive_clause: int<32>) -> ()
.. GEN:END:IRBUILDER_COMMINSTS
......
......@@ -5,15 +5,16 @@ Instruction Set
Overview
========
Mu uses a variant of static single assignment (SSA) form and a comprehensive but
low-level instruction set.
Mu uses a variant of static single assignment (SSA) form and has a comprehensive
but low-level instruction set.
Conventions
===========
If the results of an instruction is not mentioned, the instruction produces no
results. Otherwise an instruction produces one result, unless explicitly stated
otherwise.
In Mu, each instruction could produce 0 or more results, depending on the
instruction. In this chapter, if the results of an instruction is not mentioned,
the instruction produces no results. Otherwise an instruction produces one
result, unless explicitly stated otherwise.
In all examples in this chapter, the following definitions are assumed to be
present::
......@@ -345,10 +346,14 @@ Basic Operations
Binary Operations
-----------------
*binOp* ``<`` *T* ``>`` *op1* *op2* *excClause*
*binOp* *statusFlags* :sub:`opt` ``<`` *T* ``>`` *op1* *op2* *excClause*
*statusFlags* ::= ``[`` ``#N`` :sub:`opt` ``#Z`` :sub:`opt` ``#C`` :sub:`opt` ``#V`` :sub:`opt` ``]``
binOp
The binary operation.
statusFlags :sub:`opt`
*flag list*: A list of produced status flags. See below.
T
*type*: The type of both operands.
op1, op2
......@@ -356,7 +361,9 @@ op1, op2
excClause
*exception clause*: the destination for erroneous conditions.
result:
Type *T*: return the result of the computation.
- The first result: Type *T*: return the result of the computation.
- Subsequent results: As many ``int<1>`` results as the *statusFlags*.
*binOp* is one in the following table:
......@@ -383,7 +390,47 @@ result:
FREM 0xB4 FP FP remainder
========= ======== ===== ========================
TODO: Move the opcode to the IR Builder API.
*statusFlags*:
======= ========================= ====================
flag applicable to description
======= ========================= ====================
#N all integer operations negative
#Z all integer operations zero
#C ADD, SUB, MUL unsigned overflow
#V ADD, SUB, MUL signed overflow
======= ========================= ====================
The binOp instruction is the most basic arithmetic and logical operations for
integer and floating point operands of both scalar and vector form.
The binOp instruction may have 0 to 4 status flags. Each flag can be ``#N``,
``#Z``, ``#C`` or ``#V``, and must appear in this order (N before Z before C
before V).
NOTE: The reason for fixing the order of flags is to make the C-based
bundle building API simpler. In the C language, it can use the logical "or"
operator on bit flags, like ``MuBinOpStatus flags = MU_BOS_N | MU_BOS_Z |
MU_BOS_C | MU_BOS_V``.
The binOp instruction produces ``1+n`` results where ``n`` is the
number of flags. The first result is always the result of computation, and has
type *T*. Other results have type ``int<1>``, each corresponding to the next
status flags in the *statusFlags* lists.
The ``N`` and the ``Z`` flags are applicable for all **scalar integer**
operations, while ``C`` and ``V`` are only applicable for ADD, SUB and MUL on
**scalar** operands.
NOTE: Vector (SIMD) operations work very differently from scalar operations
on most architectures. They don't raise any flags. Floating point operations
usually handle exceptions by raising floating point flags (not usable for
branching or conditional operations) or returning NaN values.
For implementation reasons, it is *recommended* for the client to generate
instruction sequences that use the flags immediately after they are produced (by
SELECT, BRANCH2, or other instructions). Micro VM implementations are encouraged
to optimise for this idiom.
In all binary operations, the type of both *op1* and *op2* must have type *T*.
......@@ -396,36 +443,53 @@ vector of floating point type.
When *T* is a vector type, the operation is applied for the corresponding
elements of the two vectors.
SDIV, SREM, UDIV and UREM may have exception clause. For other operations, the
exception clause must be omitted.
Only SDIV, SREM, UDIV and UREM may have exception clauses. Other operations must
not have exception clauses.
For ADD, SUB and MUL, both operands are considered unsigned. When overflow,
returns the result modulo 2^n where n is the length of *T*.
ADD, SUB and MUL are applicable for both signed and unsigned operands. The
result is the last n bits of the mathematical result, where n is the bit length
of the integer type. The ``#C`` and the ``#V`` flags are produced for unsigned
and signed overflow, respectively. "Overflow" means the result is not equal to
the mathematical result of the unsigned/signed operation.
NOTE: Since negative numbers are encoded in the 2's complement notation,
ADD, SUB and MUL work for both signed and unsigned numbers.
ADD, SUB and MUL work for both signed and unsigned numbers. However, when
multiplying two n-bit numbers, the result can have up to 2n bits. Most
machines actually support multiplications of the form "n * n -> 2n".
However, such MUL operations need to distinguish between signed and unsigned
operands. In Mu, we follow the LLVM's tradition and suggest the client use
the idiom: when doing signed multiplication, first sign-extend both operands
from n to 2n bits, and then use the MUL instruction; for unsigned operands,
zero-extend both operands. After the operation, the higher and lower n bits
can be obtained by truncating and shifting the result.
For SDIV, SREM, UDIV and UREM, when dividing by zero, it *continues
exceptionally*. For SDIV and SREM, when overflow, the result is truncated to n
bits where n is the length of *T*.
NOTE: This means when doing 32-bit signed integer division, ``-0x80000000 /
-1 = -0x80000000``; but ``42 / 0`` will branch to the exceptional
destination, or have undefined behaviour if the exception clause is not
given.
For SHL, LSHR and ASHR, the second operand *op2* is considered unsigned. Only
the lowest m bits of *op2* are used, where m is the smallest integer that 2^m >=
n and n is the length *T*.
n and n is the length *T*. The result is truncated to n bits.
NOTE: For 32-bit and 64-bit integers, the lowest 5 and 6 bits of *op2* are
used, respectively. This is the "natural" behaviour of x86_64 and A64, but
not ARMv7.
not ARMv7. It needs special consideration to implement shifting operations
on ARMv7.
All floating point operations follow the IEEE 754 standard. They use the
default roundTiesToEven rounding attribute. If either operand is NaN, the
result is NaN. Floating point exceptions do not cause exceptional control flow
in Mu.
Semantics:
Semantics of operations:
ADD
Return the sum of the two operands.
Return the sum of the two operands.
SUB
Return the difference of the two operands.
MUL
......@@ -466,6 +530,20 @@ FDIV
FREM
Return the remainder of the two operands.
Semantics of status flags (the ``int<1>`` result is 1 if the condition is true,
0 otherwise):
N
The result is negative, i.e. the highest bit is 1.
Z
The result is zero.
C
Unsigned overflow, i.e. the result is not equal to the mathematical result
if both operands and the result are considered unsigned integers.
V
Signed overflow, i.e. the result is not equal to the mathematical result if
both operands and the result are considered signed integers.
..
For LLVM users: this is directly borrowed from LLVM. Exceptional cases,
......@@ -476,7 +554,6 @@ FREM
Example::
.const @a <@i32> = 42
.const @x <@double> = 42.0d
.const @z <@i64> = 0
......@@ -498,6 +575,42 @@ FREM
%handler():
... // handle divide-by-zero error here
Example 2, Handling overflow by branching and trapping::
%bb1():
(%b %ovf) = ADD [ #V ] <@i32> @a @I32_1
BRANCH2 %ovf %bb2(%b) %bb3(%b)
%bb2(<@i32> %b):
[%the_overflow_trap] TRAP <> KEEPALIVE (%b) // if signed overflow occured, branch here
...
%bb3(<@i32> %b):
... // otherwise, branch here
Example 3, The following snippet tries to produce many flags and does not
consume the flags immediately. It is correct and will always work as
intended, but may not always perform equally well on all platforms. For
example, on x86, the machine-level SUB, MUL and CMP instructions overwrites
the machine flags::
(%b %neg %carry %ovf) = ADD [ #N #C #V ] <@i32> @a @I32_1
%blah = SUB <@i32> @a @a
%c = SELECT <@i32> %neg @I32_1 @I32_0
%blah2 = MUL <@i32> @a @a
%d = SELECT <@i32> %carry @I32_2 @I32_0
%blah3 = LT <@i32> %a @I32_0
%e = SELECT <@i32> %ovf @I32_3 @I32_0
It is recommended to consume the flags immediately after they are produced::
.const @I32_N1 <@i32> = -1
(%b %neg %zero) = ADD [ #N #Z ] <@i32> @a @I32_1
%c1 = SELECT <@i32> %zero @I32_0 @I32_1
%c = SELECT <@i32> %neg @I32_N1 %c1
// In this example, c = b < 0 ? -1 : b == 0 ? 0 : 1
Comparison
----------
......
......@@ -646,6 +646,21 @@ The canonical definition of each instruction is in the `Instruction Set
MuVarNode opnd2,
MuExcClause exc_clause);
void (*new_binop_with_status)(MuIRBuilder *b, MuID id, MuID result_id,
MuID *status_result_ids, MuArraySize n_status_result_ids,
MuBinOpStatus status_flags,
MuBinOptr optr,
MuTypeNode ty,
MuVarNode opnd1,
MuVarNode opnd2,
MuExcClause exc_clause); /// MUAPIPARSER exc_clause:optional
typedef MuFlag MuBinOpStatus;
#define MU_BOS_N ((MuBinOpStatus)0x01)
#define MU_BOS_Z ((MuBinOpStatus)0x02)
#define MU_BOS_C ((MuBinOpStatus)0x04)
#define MU_BOS_V ((MuBinOpStatus)0x08)
typedef MuFlag MuBinOptr;
#define MU_BINOP_ADD ((MuBinOptr)0x01)
#define MU_BINOP_SUB ((MuBinOptr)0x02)
......@@ -666,7 +681,14 @@ The canonical definition of each instruction is in the `Instruction Set
#define MU_BINOP_FDIV ((MuBinOptr)0xB3)
#define MU_BINOP_FREM ((MuBinOptr)0xB4)
``new_binop`` creates a binary operation.
``new_binop`` and ``new_binop_with_status`` create a binary operation.
``result_id`` is the result of the operation; ``status_result_ids`` is an array,
each element is a desired status flag result, in the order of N, Z, C, and then
V, and ``n_status_result_ids`` is its length.
``status_flags`` is the set of desired status flags. It is the logical OR
(``|``) of the ``MuBinOIpStatus`` constants.
``optr`` is the binary operator. ``ty`` is the operand type. ``opnd1`` and
``opnd2`` are the two operands.
......@@ -674,6 +696,9 @@ The canonical definition of each instruction is in the `Instruction Set
``exc_clause`` is the **optional** exception clause to handle the
division-by-zero and overflow case of division and remainder operations.
``new_binop`` is equivalent to ``new_binop_with_status`` with
``status_result_ids == NULL, n_status_result_ids == 0, status_flags == 0``.
::
void (*new_cmp )(MuIRBuilder *b, MuID id, MuID result_id,
......
......@@ -149,6 +149,12 @@ typedef _MuTrapHandler_Func* MuTrapHandler;
// Binary operators
typedef MuFlag MuBinOpStatus;
#define MU_BOS_N ((MuBinOpStatus)0x01)
#define MU_BOS_Z ((MuBinOpStatus)0x02)
#define MU_BOS_C ((MuBinOpStatus)0x04)
#define MU_BOS_V ((MuBinOpStatus)0x08)
typedef MuFlag MuBinOptr;
#define MU_BINOP_ADD ((MuBinOptr)0x01)
#define MU_BINOP_SUB ((MuBinOptr)0x02)
......@@ -596,6 +602,14 @@ struct MuIRBuilder {
MuVarNode opnd1,
MuVarNode opnd2,
MuExcClause exc_clause); /// MUAPIPARSER exc_clause:optional
void (*new_binop_with_status)(MuIRBuilder *b, MuID id, MuID result_id,
MuID *status_result_ids, MuArraySize n_status_result_ids,
MuBinOpStatus status_flags,
MuBinOptr optr,
MuTypeNode ty,
MuVarNode opnd1,
MuVarNode opnd2,
MuExcClause exc_clause); /// MUAPIPARSER exc_clause:optional
void (*new_cmp )(MuIRBuilder *b, MuID id, MuID result_id,
MuCmpOptr optr,
MuTypeNode ty,
......@@ -818,42 +832,43 @@ struct MuIRBuilder {
#define MU_CI_UVM_IRBUILDER_NEW_NSC_PASS_VALUES ((MuCommInst)0x328) /// MUAPIPARSER muname:@uvm.irbuilder.new_nsc_pass_values
#define MU_CI_UVM_IRBUILDER_NEW_NSC_THROW_EXC ((MuCommInst)0x329) /// MUAPIPARSER muname:@uvm.irbuilder.new_nsc_throw_exc
#define MU_CI_UVM_IRBUILDER_NEW_BINOP ((MuCommInst)0x32a) /// MUAPIPARSER muname:@uvm.irbuilder.new_binop
#define MU_CI_UVM_IRBUILDER_NEW_CMP ((MuCommInst)0x32b) /// MUAPIPARSER muname:@uvm.irbuilder.new_cmp
#define MU_CI_UVM_IRBUILDER_NEW_CONV ((MuCommInst)0x32c) /// MUAPIPARSER muname:@uvm.irbuilder.new_conv
#define MU_CI_UVM_IRBUILDER_NEW_SELECT ((MuCommInst)0x32d) /// MUAPIPARSER muname:@uvm.irbuilder.new_select
#define MU_CI_UVM_IRBUILDER_NEW_BRANCH ((MuCommInst)0x32e) /// MUAPIPARSER muname:@uvm.irbuilder.new_branch
#define MU_CI_UVM_IRBUILDER_NEW_BRANCH2 ((MuCommInst)0x32f) /// MUAPIPARSER muname:@uvm.irbuilder.new_branch2
#define MU_CI_UVM_IRBUILDER_NEW_SWITCH ((MuCommInst)0x330) /// MUAPIPARSER muname:@uvm.irbuilder.new_switch
#define MU_CI_UVM_IRBUILDER_NEW_CALL ((MuCommInst)0x331) /// MUAPIPARSER muname:@uvm.irbuilder.new_call
#define MU_CI_UVM_IRBUILDER_NEW_TAILCALL ((MuCommInst)0x332) /// MUAPIPARSER muname:@uvm.irbuilder.new_tailcall
#define MU_CI_UVM_IRBUILDER_NEW_RET ((MuCommInst)0x333) /// MUAPIPARSER muname:@uvm.irbuilder.new_ret
#define MU_CI_UVM_IRBUILDER_NEW_THROW ((MuCommInst)0x334) /// MUAPIPARSER muname:@uvm.irbuilder.new_throw
#define MU_CI_UVM_IRBUILDER_NEW_EXTRACTVALUE ((MuCommInst)0x335) /// MUAPIPARSER muname:@uvm.irbuilder.new_extractvalue
#define MU_CI_UVM_IRBUILDER_NEW_INSERTVALUE ((MuCommInst)0x336) /// MUAPIPARSER muname:@uvm.irbuilder.new_insertvalue
#define MU_CI_UVM_IRBUILDER_NEW_EXTRACTELEMENT ((MuCommInst)0x337) /// MUAPIPARSER muname:@uvm.irbuilder.new_extractelement
#define MU_CI_UVM_IRBUILDER_NEW_INSERTELEMENT ((MuCommInst)0x338) /// MUAPIPARSER muname:@uvm.irbuilder.new_insertelement
#define MU_CI_UVM_IRBUILDER_NEW_SHUFFLEVECTOR ((MuCommInst)0x339) /// MUAPIPARSER muname:@uvm.irbuilder.new_shufflevector
#define MU_CI_UVM_IRBUILDER_NEW_NEW ((MuCommInst)0x33a) /// MUAPIPARSER muname:@uvm.irbuilder.new_new
#define MU_CI_UVM_IRBUILDER_NEW_NEWHYBRID ((MuCommInst)0x33b) /// MUAPIPARSER muname:@uvm.irbuilder.new_newhybrid
#define MU_CI_UVM_IRBUILDER_NEW_ALLOCA ((MuCommInst)0x33c) /// MUAPIPARSER muname:@uvm.irbuilder.new_alloca
#define MU_CI_UVM_IRBUILDER_NEW_ALLOCAHYBRID ((MuCommInst)0x33d) /// MUAPIPARSER muname:@uvm.irbuilder.new_allocahybrid
#define MU_CI_UVM_IRBUILDER_NEW_GETIREF ((MuCommInst)0x33e) /// MUAPIPARSER muname:@uvm.irbuilder.new_getiref
#define MU_CI_UVM_IRBUILDER_NEW_GETFIELDIREF ((MuCommInst)0x33f) /// MUAPIPARSER muname:@uvm.irbuilder.new_getfieldiref
#define MU_CI_UVM_IRBUILDER_NEW_GETELEMIREF ((MuCommInst)0x340) /// MUAPIPARSER muname:@uvm.irbuilder.new_getelemiref
#define MU_CI_UVM_IRBUILDER_NEW_SHIFTIREF ((MuCommInst)0x341) /// MUAPIPARSER muname:@uvm.irbuilder.new_shiftiref
#define MU_CI_UVM_IRBUILDER_NEW_GETVARPARTIREF ((MuCommInst)0x342) /// MUAPIPARSER muname:@uvm.irbuilder.new_getvarpartiref
#define MU_CI_UVM_IRBUILDER_NEW_LOAD ((MuCommInst)0x343) /// MUAPIPARSER muname:@uvm.irbuilder.new_load
#define MU_CI_UVM_IRBUILDER_NEW_STORE ((MuCommInst)0x344) /// MUAPIPARSER muname:@uvm.irbuilder.new_store
#define MU_CI_UVM_IRBUILDER_NEW_CMPXCHG ((MuCommInst)0x345) /// MUAPIPARSER muname:@uvm.irbuilder.new_cmpxchg
#define MU_CI_UVM_IRBUILDER_NEW_ATOMICRMW ((MuCommInst)0x346) /// MUAPIPARSER muname:@uvm.irbuilder.new_atomicrmw
#define MU_CI_UVM_IRBUILDER_NEW_FENCE ((MuCommInst)0x347) /// MUAPIPARSER muname:@uvm.irbuilder.new_fence
#define MU_CI_UVM_IRBUILDER_NEW_TRAP ((MuCommInst)0x348) /// MUAPIPARSER muname:@uvm.irbuilder.new_trap
#define MU_CI_UVM_IRBUILDER_NEW_WATCHPOINT ((MuCommInst)0x349) /// MUAPIPARSER muname:@uvm.irbuilder.new_watchpoint
#define MU_CI_UVM_IRBUILDER_NEW_WPBRANCH ((MuCommInst)0x34a) /// MUAPIPARSER muname:@uvm.irbuilder.new_wpbranch
#define MU_CI_UVM_IRBUILDER_NEW_CCALL ((MuCommInst)0x34b) /// MUAPIPARSER muname:@uvm.irbuilder.new_ccall
#define MU_CI_UVM_IRBUILDER_NEW_NEWTHREAD ((MuCommInst)0x34c) /// MUAPIPARSER muname:@uvm.irbuilder.new_newthread
#define MU_CI_UVM_IRBUILDER_NEW_SWAPSTACK ((MuCommInst)0x34d) /// MUAPIPARSER muname:@uvm.irbuilder.new_swapstack
#define MU_CI_UVM_IRBUILDER_NEW_COMMINST ((MuCommInst)0x34e) /// MUAPIPARSER muname:@uvm.irbuilder.new_comminst
#define MU_CI_UVM_IRBUILDER_NEW_BINOP_WITH_STATUS ((MuCommInst)0x32b) /// MUAPIPARSER muname:@uvm.irbuilder.new_binop_with_status
#define MU_CI_UVM_IRBUILDER_NEW_CMP ((MuCommInst)0x32c) /// MUAPIPARSER muname:@uvm.irbuilder.new_cmp
#define MU_CI_UVM_IRBUILDER_NEW_CONV ((MuCommInst)0x32d) /// MUAPIPARSER muname:@uvm.irbuilder.new_conv
#define MU_CI_UVM_IRBUILDER_NEW_SELECT ((MuCommInst)0x32e) /// MUAPIPARSER muname:@uvm.irbuilder.new_select
#define MU_CI_UVM_IRBUILDER_NEW_BRANCH ((MuCommInst)0x32f) /// MUAPIPARSER muname:@uvm.irbuilder.new_branch
#define MU_CI_UVM_IRBUILDER_NEW_BRANCH2 ((MuCommInst)0x330) /// MUAPIPARSER muname:@uvm.irbuilder.new_branch2
#define MU_CI_UVM_IRBUILDER_NEW_SWITCH ((MuCommInst)0x331) /// MUAPIPARSER muname:@uvm.irbuilder.new_switch
#define MU_CI_UVM_IRBUILDER_NEW_CALL ((MuCommInst)0x332) /// MUAPIPARSER muname:@uvm.irbuilder.new_call
#define MU_CI_UVM_IRBUILDER_NEW_TAILCALL ((MuCommInst)0x333) /// MUAPIPARSER muname:@uvm.irbuilder.new_tailcall
#define MU_CI_UVM_IRBUILDER_NEW_RET ((MuCommInst)0x334) /// MUAPIPARSER muname:@uvm.irbuilder.new_ret
#define MU_CI_UVM_IRBUILDER_NEW_THROW ((MuCommInst)0x335) /// MUAPIPARSER muname:@uvm.irbuilder.new_throw
#define MU_CI_UVM_IRBUILDER_NEW_EXTRACTVALUE ((MuCommInst)0x336) /// MUAPIPARSER muname:@uvm.irbuilder.new_extractvalue
#define MU_CI_UVM_IRBUILDER_NEW_INSERTVALUE ((MuCommInst)0x337) /// MUAPIPARSER muname:@uvm.irbuilder.new_insertvalue
#define MU_CI_UVM_IRBUILDER_NEW_EXTRACTELEMENT ((MuCommInst)0x338) /// MUAPIPARSER muname:@uvm.irbuilder.new_extractelement
#define MU_CI_UVM_IRBUILDER_NEW_INSERTELEMENT ((MuCommInst)0x339) /// MUAPIPARSER muname:@uvm.irbuilder.new_insertelement
#define MU_CI_UVM_IRBUILDER_NEW_SHUFFLEVECTOR ((MuCommInst)0x33a) /// MUAPIPARSER muname:@uvm.irbuilder.new_shufflevector
#define MU_CI_UVM_IRBUILDER_NEW_NEW ((MuCommInst)0x33b) /// MUAPIPARSER muname:@uvm.irbuilder.new_new
#define MU_CI_UVM_IRBUILDER_NEW_NEWHYBRID ((MuCommInst)0x33c) /// MUAPIPARSER muname:@uvm.irbuilder.new_newhybrid
#define MU_CI_UVM_IRBUILDER_NEW_ALLOCA ((MuCommInst)0x33d) /// MUAPIPARSER muname:@uvm.irbuilder.new_alloca
#define MU_CI_UVM_IRBUILDER_NEW_ALLOCAHYBRID ((MuCommInst)0x33e) /// MUAPIPARSER muname:@uvm.irbuilder.new_allocahybrid
#define MU_CI_UVM_IRBUILDER_NEW_GETIREF ((MuCommInst)0x33f) /// MUAPIPARSER muname:@uvm.irbuilder.new_getiref
#define MU_CI_UVM_IRBUILDER_NEW_GETFIELDIREF ((MuCommInst)0x340) /// MUAPIPARSER muname:@uvm.irbuilder.new_getfieldiref
#define MU_CI_UVM_IRBUILDER_NEW_GETELEMIREF ((MuCommInst)0x341) /// MUAPIPARSER muname:@uvm.irbuilder.new_getelemiref
#define MU_CI_UVM_IRBUILDER_NEW_SHIFTIREF ((MuCommInst)0x342) /// MUAPIPARSER muname:@uvm.irbuilder.new_shiftiref
#define MU_CI_UVM_IRBUILDER_NEW_GETVARPARTIREF ((MuCommInst)0x343) /// MUAPIPARSER muname:@uvm.irbuilder.new_getvarpartiref
#define MU_CI_UVM_IRBUILDER_NEW_LOAD ((MuCommInst)0x344) /// MUAPIPARSER muname:@uvm.irbuilder.new_load
#define MU_CI_UVM_IRBUILDER_NEW_STORE ((MuCommInst)0x345) /// MUAPIPARSER muname:@uvm.irbuilder.new_store
#define MU_CI_UVM_IRBUILDER_NEW_CMPXCHG ((MuCommInst)0x346) /// MUAPIPARSER muname:@uvm.irbuilder.new_cmpxchg
#define MU_CI_UVM_IRBUILDER_NEW_ATOMICRMW ((MuCommInst)0x347) /// MUAPIPARSER muname:@uvm.irbuilder.new_atomicrmw
#define MU_CI_UVM_IRBUILDER_NEW_FENCE ((MuCommInst)0x348) /// MUAPIPARSER muname:@uvm.irbuilder.new_fence
#define MU_CI_UVM_IRBUILDER_NEW_TRAP ((MuCommInst)0x349) /// MUAPIPARSER muname:@uvm.irbuilder.new_trap
#define MU_CI_UVM_IRBUILDER_NEW_WATCHPOINT ((MuCommInst)0x34a) /// MUAPIPARSER muname:@uvm.irbuilder.new_watchpoint
#define MU_CI_UVM_IRBUILDER_NEW_WPBRANCH ((MuCommInst)0x34b) /// MUAPIPARSER muname:@uvm.irbuilder.new_wpbranch
#define MU_CI_UVM_IRBUILDER_NEW_CCALL ((MuCommInst)0x34c) /// MUAPIPARSER muname:@uvm.irbuilder.new_ccall
#define MU_CI_UVM_IRBUILDER_NEW_NEWTHREAD ((MuCommInst)0x34d) /// MUAPIPARSER muname:@uvm.irbuilder.new_newthread
#define MU_CI_UVM_IRBUILDER_NEW_SWAPSTACK ((MuCommInst)0x34e) /// MUAPIPARSER muname:@uvm.irbuilder.new_swapstack
#define MU_CI_UVM_IRBUILDER_NEW_COMMINST ((MuCommInst)0x34f) /// MUAPIPARSER muname:@uvm.irbuilder.new_comminst
/// GEN:END:COMMINSTS
#ifdef __cplusplus
......
......@@ -22,6 +22,7 @@ _type_map = {
"MuBool" : "int<32>",
"MuWPID" : "int<32>",
"MuArraySize" : "int<64>",
"MuBinOpStatus" : "int<32>",
"MuBinOptr" : "int<32>",
"MuCmpOptr" : "int<32>",
"MuConvOptr" : "int<32>",
......
......@@ -72,6 +72,7 @@ _top_level_structs = ["MuVM", "MuCtx", "MuIRBuilder"]
_enums = [(typename, re.compile(regex)) for typename, regex in [
("MuTrapHandlerResult", r'^MU_(THREAD|REBIND)'),
("MuDestKind", r'^MU_DEST_'),
("MuBinOpStatus", r'^MU_BOS_'),
("MuBinOptr", r'^MU_BINOP_'),
("MuCmpOptr", r'^MU_CMP_'),
("MuConvOptr", r'^MU_CONV_'),
......
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