Merge remote-tracking branch 'origin/master' into no_std
This commit is contained in:
@@ -2,6 +2,10 @@ language: rust
|
|||||||
rust:
|
rust:
|
||||||
- stable
|
- stable
|
||||||
- beta
|
- beta
|
||||||
|
- nightly
|
||||||
|
matrix:
|
||||||
|
allow_failures:
|
||||||
|
- rust: nightly
|
||||||
dist: trusty
|
dist: trusty
|
||||||
sudo: false
|
sudo: false
|
||||||
addons:
|
addons:
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ Cretonne Code Generator
|
|||||||
=======================
|
=======================
|
||||||
|
|
||||||
Cretonne is a low-level retargetable code generator. It translates a `target-independent
|
Cretonne is a low-level retargetable code generator. It translates a `target-independent
|
||||||
intermediate language <https://cretonne.readthedocs.io/en/latest/langref.html>`_ into executable
|
intermediate representation <https://cretonne.readthedocs.io/en/latest/langref.html>`_ into executable
|
||||||
machine code.
|
machine code.
|
||||||
|
|
||||||
*This is a work in progress that is not yet functional.*
|
*This is a work in progress that is not yet functional.*
|
||||||
@@ -16,6 +16,10 @@ machine code.
|
|||||||
:target: https://travis-ci.org/Cretonne/cretonne
|
:target: https://travis-ci.org/Cretonne/cretonne
|
||||||
:alt: Build Status
|
:alt: Build Status
|
||||||
|
|
||||||
|
.. image:: https://badges.gitter.im/Cretonne/cretonne.png
|
||||||
|
:target: https://gitter.im/Cretonne/Lobby/~chat
|
||||||
|
:alt: Gitter chat
|
||||||
|
|
||||||
For more information, see `the documentation
|
For more information, see `the documentation
|
||||||
<https://cretonne.readthedocs.io/en/latest/?badge=latest>`_.
|
<https://cretonne.readthedocs.io/en/latest/?badge=latest>`_.
|
||||||
|
|
||||||
|
|||||||
10
check-clippy.sh
Executable file
10
check-clippy.sh
Executable file
@@ -0,0 +1,10 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Usage: check-clippy.sh [--install]
|
||||||
|
|
||||||
|
if cargo install --list | tee /dev/null | grep -q "^clippy v0"; then
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
@@ -22,11 +22,11 @@ set -euo pipefail
|
|||||||
# operation, however that doesn't appear to be possible through "cargo fmt").
|
# operation, however that doesn't appear to be possible through "cargo fmt").
|
||||||
VERS="0.9.0"
|
VERS="0.9.0"
|
||||||
|
|
||||||
if cargo install --list | grep -q "^rustfmt v$VERS"; then
|
if cargo install --list | tee /dev/null | grep -q "^rustfmt v$VERS"; then
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$1" != "--install" ]; then
|
if [[ ${1:-""} != "--install" ]]; then
|
||||||
echo "********************************************************************"
|
echo "********************************************************************"
|
||||||
echo "* Please install rustfmt v$VERS to verify formatting. *"
|
echo "* Please install rustfmt v$VERS to verify formatting. *"
|
||||||
echo "* If a newer version of rustfmt is available, update this script. *"
|
echo "* If a newer version of rustfmt is available, update this script. *"
|
||||||
|
|||||||
7
clippy-all.sh
Executable file
7
clippy-all.sh
Executable file
@@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Check all sources with clippy.
|
||||||
|
# In the cton-util crate (root dir) clippy will only work with nightly cargo -
|
||||||
|
# there is a bug where it will reject the commands passed to it by cargo 0.25.0
|
||||||
|
cargo +nightly clippy --all
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "cretonne-tools"
|
name = "cretonne-tools"
|
||||||
authors = ["The Cretonne Project Developers"]
|
authors = ["The Cretonne Project Developers"]
|
||||||
version = "0.3.4"
|
version = "0.4.1"
|
||||||
description = "Binaries for testing the Cretonne library"
|
description = "Binaries for testing the Cretonne library"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
documentation = "https://cretonne.readthedocs.io/"
|
documentation = "https://cretonne.readthedocs.io/"
|
||||||
@@ -13,18 +13,18 @@ name = "cton-util"
|
|||||||
path = "src/cton-util.rs"
|
path = "src/cton-util.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cretonne = { path = "lib/cretonne", version = "0.3.4" }
|
cretonne = { path = "lib/cretonne", version = "0.4.1" }
|
||||||
cretonne-reader = { path = "lib/reader", version = "0.3.4" }
|
cretonne-reader = { path = "lib/reader", version = "0.4.1" }
|
||||||
cretonne-frontend = { path = "lib/frontend", version = "0.3.4" }
|
cretonne-frontend = { path = "lib/frontend", version = "0.4.1" }
|
||||||
cretonne-wasm = { path = "lib/wasm", version = "0.3.4" }
|
cretonne-wasm = { path = "lib/wasm", version = "0.4.1" }
|
||||||
cretonne-native = { path = "lib/native", version = "0.3.4" }
|
cretonne-native = { path = "lib/native", version = "0.4.1" }
|
||||||
filecheck = { path = "lib/filecheck" }
|
cretonne-filetests = { path = "lib/filetests", version = "0.4.1" }
|
||||||
|
filecheck = "0.2.1"
|
||||||
docopt = "0.8.0"
|
docopt = "0.8.0"
|
||||||
serde = "1.0.8"
|
serde = "1.0.8"
|
||||||
serde_derive = "1.0.8"
|
serde_derive = "1.0.8"
|
||||||
num_cpus = "1.5.1"
|
|
||||||
tempdir = "0.3.5"
|
tempdir = "0.3.5"
|
||||||
term = "0.5"
|
term = "0.5.1"
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
|
|
||||||
|
|||||||
1
cranelift/clippy.toml
Normal file
1
cranelift/clippy.toml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
doc-valid-idents = [ "WebAssembly", "NaN", "SetCC" ]
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
test verifier
|
test verifier
|
||||||
|
|
||||||
function %gcd(i32 uext, i32 uext) -> i32 uext native {
|
function %gcd(i32 uext, i32 uext) -> i32 uext system_v {
|
||||||
fn1 = function %divmod(i32 uext, i32 uext) -> i32 uext, i32 uext
|
fn1 = function %divmod(i32 uext, i32 uext) -> i32 uext, i32 uext
|
||||||
|
|
||||||
ebb1(v1: i32, v2: i32):
|
ebb1(v1: i32, v2: i32):
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ highlighting some of the differences and similarities. Both projects:
|
|||||||
- Use an ISA-agnostic input language in order to mostly abstract away the
|
- Use an ISA-agnostic input language in order to mostly abstract away the
|
||||||
differences between target instruction set architectures.
|
differences between target instruction set architectures.
|
||||||
- Depend extensively on SSA form.
|
- Depend extensively on SSA form.
|
||||||
- Have both textual and in-memory forms of their primary intermediate language.
|
- Have both textual and in-memory forms of their primary intermediate
|
||||||
(LLVM also has a binary bitcode format; Cretonne doesn't.)
|
representation. (LLVM also has a binary bitcode format; Cretonne doesn't.)
|
||||||
- Can target multiple ISAs.
|
- Can target multiple ISAs.
|
||||||
- Can cross-compile by default without rebuilding the code generator.
|
- Can cross-compile by default without rebuilding the code generator.
|
||||||
|
|
||||||
@@ -41,8 +41,8 @@ LLVM uses multiple intermediate representations as it translates a program to
|
|||||||
binary machine code:
|
binary machine code:
|
||||||
|
|
||||||
`LLVM IR <https://llvm.org/docs/LangRef.html>`_
|
`LLVM IR <https://llvm.org/docs/LangRef.html>`_
|
||||||
This is the primary intermediate language which has textual, binary, and
|
This is the primary intermediate representation which has textual, binary, and
|
||||||
in-memory representations. It serves two main purposes:
|
in-memory forms. It serves two main purposes:
|
||||||
|
|
||||||
- An ISA-agnostic, stable(ish) input language that front ends can generate
|
- An ISA-agnostic, stable(ish) input language that front ends can generate
|
||||||
easily.
|
easily.
|
||||||
@@ -89,9 +89,9 @@ representation. Some target ISAs have a fast instruction selector that can
|
|||||||
translate simple code directly to MachineInstrs, bypassing SelectionDAG when
|
translate simple code directly to MachineInstrs, bypassing SelectionDAG when
|
||||||
possible.
|
possible.
|
||||||
|
|
||||||
:doc:`Cretonne <langref>` uses a single intermediate language to cover these
|
:doc:`Cretonne <langref>` uses a single intermediate representation to cover
|
||||||
levels of abstraction. This is possible in part because of Cretonne's smaller
|
these levels of abstraction. This is possible in part because of Cretonne's
|
||||||
scope.
|
smaller scope.
|
||||||
|
|
||||||
- Cretonne does not provide assemblers and disassemblers, so it is not
|
- Cretonne does not provide assemblers and disassemblers, so it is not
|
||||||
necessary to be able to represent every weird instruction in an ISA. Only
|
necessary to be able to represent every weird instruction in an ISA. Only
|
||||||
@@ -102,7 +102,7 @@ scope.
|
|||||||
- SSA form is preserved throughout. After register allocation, each SSA value
|
- SSA form is preserved throughout. After register allocation, each SSA value
|
||||||
is annotated with an assigned ISA register or stack slot.
|
is annotated with an assigned ISA register or stack slot.
|
||||||
|
|
||||||
The Cretonne intermediate language is similar to LLVM IR, but at a slightly
|
The Cretonne intermediate representation is similar to LLVM IR, but at a slightly
|
||||||
lower level of abstraction.
|
lower level of abstraction.
|
||||||
|
|
||||||
Program structure
|
Program structure
|
||||||
@@ -112,12 +112,12 @@ In LLVM IR, the largest representable unit is the *module* which corresponds
|
|||||||
more or less to a C translation unit. It is a collection of functions and
|
more or less to a C translation unit. It is a collection of functions and
|
||||||
global variables that may contain references to external symbols too.
|
global variables that may contain references to external symbols too.
|
||||||
|
|
||||||
In Cretonne IL, the largest representable unit is the *function*. This is so
|
In Cretonne IR, the largest representable unit is the *function*. This is so
|
||||||
that functions can easily be compiled in parallel without worrying about
|
that functions can easily be compiled in parallel without worrying about
|
||||||
references to shared data structures. Cretonne does not have any
|
references to shared data structures. Cretonne does not have any
|
||||||
inter-procedural optimizations like inlining.
|
inter-procedural optimizations like inlining.
|
||||||
|
|
||||||
An LLVM IR function is a graph of *basic blocks*. A Cretonne IL function is a
|
An LLVM IR function is a graph of *basic blocks*. A Cretonne IR function is a
|
||||||
graph of *extended basic blocks* that may contain internal branch instructions.
|
graph of *extended basic blocks* that may contain internal branch instructions.
|
||||||
The main difference is that an LLVM conditional branch instruction has two
|
The main difference is that an LLVM conditional branch instruction has two
|
||||||
target basic blocks---a true and a false edge. A Cretonne branch instruction
|
target basic blocks---a true and a false edge. A Cretonne branch instruction
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
# Sphinx domain for documenting compiler intermediate languages.
|
# Sphinx domain for documenting compiler intermediate representations.
|
||||||
#
|
#
|
||||||
# This defines a 'cton' Sphinx domain with the following directives and roles:
|
# This defines a 'cton' Sphinx domain with the following directives and roles:
|
||||||
#
|
#
|
||||||
@@ -29,10 +29,10 @@ import sphinx.ext.autodoc
|
|||||||
|
|
||||||
class CtonObject(ObjectDescription):
|
class CtonObject(ObjectDescription):
|
||||||
"""
|
"""
|
||||||
Any kind of Cretonne IL object.
|
Any kind of Cretonne IR object.
|
||||||
|
|
||||||
This is a shared base class for the different kinds of indexable objects
|
This is a shared base class for the different kinds of indexable objects
|
||||||
in the Cretonne IL reference.
|
in the Cretonne IR reference.
|
||||||
"""
|
"""
|
||||||
option_spec = {
|
option_spec = {
|
||||||
'noindex': directives.flag,
|
'noindex': directives.flag,
|
||||||
@@ -98,7 +98,7 @@ def parse_type(name, signode):
|
|||||||
|
|
||||||
|
|
||||||
class CtonType(CtonObject):
|
class CtonType(CtonObject):
|
||||||
"""A Cretonne IL type description."""
|
"""A Cretonne IR type description."""
|
||||||
|
|
||||||
def handle_signature(self, sig, signode):
|
def handle_signature(self, sig, signode):
|
||||||
"""
|
"""
|
||||||
@@ -112,7 +112,7 @@ class CtonType(CtonObject):
|
|||||||
return name
|
return name
|
||||||
|
|
||||||
def get_index_text(self, name):
|
def get_index_text(self, name):
|
||||||
return name + ' (IL type)'
|
return name + ' (IR type)'
|
||||||
|
|
||||||
|
|
||||||
sep_equal = re.compile('\s*=\s*')
|
sep_equal = re.compile('\s*=\s*')
|
||||||
@@ -127,7 +127,7 @@ def parse_params(s, signode):
|
|||||||
|
|
||||||
|
|
||||||
class CtonInst(CtonObject):
|
class CtonInst(CtonObject):
|
||||||
"""A Cretonne IL instruction."""
|
"""A Cretonne IR instruction."""
|
||||||
|
|
||||||
doc_field_types = [
|
doc_field_types = [
|
||||||
TypedField('argument', label=l_('Arguments'),
|
TypedField('argument', label=l_('Arguments'),
|
||||||
@@ -176,11 +176,11 @@ class CtonInst(CtonObject):
|
|||||||
|
|
||||||
|
|
||||||
class CtonInstGroup(CtonObject):
|
class CtonInstGroup(CtonObject):
|
||||||
"""A Cretonne IL instruction group."""
|
"""A Cretonne IR instruction group."""
|
||||||
|
|
||||||
|
|
||||||
class CretonneDomain(Domain):
|
class CretonneDomain(Domain):
|
||||||
"""Cretonne domain for intermediate language objects."""
|
"""Cretonne domain for IR objects."""
|
||||||
name = 'cton'
|
name = 'cton'
|
||||||
label = 'Cretonne'
|
label = 'Cretonne'
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
test verifier
|
test verifier
|
||||||
|
|
||||||
function %average(i32, i32) -> f32 native {
|
function %average(i32, i32) -> f32 system_v {
|
||||||
ss1 = explicit_slot 8 ; Stack slot for ``sum``.
|
ss1 = explicit_slot 8 ; Stack slot for ``sum``.
|
||||||
|
|
||||||
ebb1(v1: i32, v2: i32):
|
ebb1(v1: i32, v2: i32):
|
||||||
|
|||||||
@@ -5,19 +5,19 @@ Cretonne Language Reference
|
|||||||
.. default-domain:: cton
|
.. default-domain:: cton
|
||||||
.. highlight:: cton
|
.. highlight:: cton
|
||||||
|
|
||||||
The Cretonne intermediate language (:term:`IL`) has two equivalent
|
The Cretonne intermediate representation (:term:`IR`) has two primary forms:
|
||||||
representations: an *in-memory data structure* that the code generator library
|
an *in-memory data structure* that the code generator library is using, and a
|
||||||
is using, and a *text format* which is used for test cases and debug output.
|
*text format* which is used for test cases and debug output.
|
||||||
Files containing Cretonne textual IL have the ``.cton`` filename extension.
|
Files containing Cretonne textual IR have the ``.cton`` filename extension.
|
||||||
|
|
||||||
This reference uses the text format to describe IL semantics but glosses over
|
This reference uses the text format to describe IR semantics but glosses over
|
||||||
the finer details of the lexical and syntactic structure of the format.
|
the finer details of the lexical and syntactic structure of the format.
|
||||||
|
|
||||||
|
|
||||||
Overall structure
|
Overall structure
|
||||||
=================
|
=================
|
||||||
|
|
||||||
Cretonne compiles functions independently. A ``.cton`` IL file may contain
|
Cretonne compiles functions independently. A ``.cton`` IR file may contain
|
||||||
multiple functions, and the programmatic API can create multiple function
|
multiple functions, and the programmatic API can create multiple function
|
||||||
handles at the same time, but the functions don't share any data or reference
|
handles at the same time, but the functions don't share any data or reference
|
||||||
each other directly.
|
each other directly.
|
||||||
@@ -27,7 +27,7 @@ This is a simple C function that computes the average of an array of floats:
|
|||||||
.. literalinclude:: example.c
|
.. literalinclude:: example.c
|
||||||
:language: c
|
:language: c
|
||||||
|
|
||||||
Here is the same function compiled into Cretonne IL:
|
Here is the same function compiled into Cretonne IR:
|
||||||
|
|
||||||
.. literalinclude:: example.cton
|
.. literalinclude:: example.cton
|
||||||
:language: cton
|
:language: cton
|
||||||
@@ -77,7 +77,7 @@ variable value for the next iteration.
|
|||||||
|
|
||||||
The `cton_frontend` crate contains utilities for translating from programs
|
The `cton_frontend` crate contains utilities for translating from programs
|
||||||
containing multiple assignments to the same variables into SSA form for
|
containing multiple assignments to the same variables into SSA form for
|
||||||
Cretonne :term:`IL`.
|
Cretonne :term:`IR`.
|
||||||
|
|
||||||
Such variables can also be presented to Cretonne as :term:`stack slot`\s.
|
Such variables can also be presented to Cretonne as :term:`stack slot`\s.
|
||||||
Stack slots are accessed with the :inst:`stack_store` and :inst:`stack_load`
|
Stack slots are accessed with the :inst:`stack_store` and :inst:`stack_load`
|
||||||
@@ -303,7 +303,7 @@ indicate the different kinds of immediate operands on an instruction.
|
|||||||
A floating point condition code. See the :inst:`fcmp` instruction for details.
|
A floating point condition code. See the :inst:`fcmp` instruction for details.
|
||||||
|
|
||||||
The two IEEE floating point immediate types :type:`ieee32` and :type:`ieee64`
|
The two IEEE floating point immediate types :type:`ieee32` and :type:`ieee64`
|
||||||
are displayed as hexadecimal floating point literals in the textual :term:`IL`
|
are displayed as hexadecimal floating point literals in the textual :term:`IR`
|
||||||
format. Decimal floating point literals are not allowed because some computer
|
format. Decimal floating point literals are not allowed because some computer
|
||||||
systems can round differently when converting to binary. The hexadecimal
|
systems can round differently when converting to binary. The hexadecimal
|
||||||
floating point format is mostly the same as the one used by C99, but extended
|
floating point format is mostly the same as the one used by C99, but extended
|
||||||
@@ -400,11 +400,11 @@ convention:
|
|||||||
param : type [paramext] [paramspecial]
|
param : type [paramext] [paramspecial]
|
||||||
paramext : "uext" | "sext"
|
paramext : "uext" | "sext"
|
||||||
paramspecial : "sret" | "link" | "fp" | "csr" | "vmctx"
|
paramspecial : "sret" | "link" | "fp" | "csr" | "vmctx"
|
||||||
callconv : "native" | "spiderwasm"
|
callconv : "system_v" | "spiderwasm"
|
||||||
|
|
||||||
Parameters and return values have flags whose meaning is mostly target
|
Parameters and return values have flags whose meaning is mostly target
|
||||||
dependent. They make it possible to call native functions on the target
|
dependent. These flags support interfacing with code produced by other
|
||||||
platform. When calling other Cretonne functions, the flags are not necessary.
|
compilers.
|
||||||
|
|
||||||
Functions that are called directly must be declared in the :term:`function
|
Functions that are called directly must be declared in the :term:`function
|
||||||
preamble`:
|
preamble`:
|
||||||
@@ -563,7 +563,7 @@ runtime data structures.
|
|||||||
alignment for storing a pointer.
|
alignment for storing a pointer.
|
||||||
|
|
||||||
Chains of ``deref`` global variables are possible, but cycles are not
|
Chains of ``deref`` global variables are possible, but cycles are not
|
||||||
allowed. They will be caught by the IL verifier.
|
allowed. They will be caught by the IR verifier.
|
||||||
|
|
||||||
:arg BaseGV: Global variable containing the base pointer.
|
:arg BaseGV: Global variable containing the base pointer.
|
||||||
:arg Offset: Byte offset from the loaded base pointer to the global
|
:arg Offset: Byte offset from the loaded base pointer to the global
|
||||||
@@ -654,6 +654,11 @@ trap when accessed.
|
|||||||
address space reserved for the heap, not including the guard pages.
|
address space reserved for the heap, not including the guard pages.
|
||||||
:arg GuardBytes: Size of the guard pages in bytes.
|
:arg GuardBytes: Size of the guard pages in bytes.
|
||||||
|
|
||||||
|
When the base is a global variable, it must be :term:`accessible` and naturally
|
||||||
|
aligned for a pointer value.
|
||||||
|
|
||||||
|
The ``reserved_reg`` option is not yet implemented.
|
||||||
|
|
||||||
Dynamic heaps
|
Dynamic heaps
|
||||||
~~~~~~~~~~~~~
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
@@ -672,6 +677,11 @@ is resized. The bound of a dynamic heap is stored in a global variable.
|
|||||||
:arg BoundGV: Global variable containing the current heap bound in bytes.
|
:arg BoundGV: Global variable containing the current heap bound in bytes.
|
||||||
:arg GuardBytes: Size of the guard pages in bytes.
|
:arg GuardBytes: Size of the guard pages in bytes.
|
||||||
|
|
||||||
|
When the base is a global variable, it must be :term:`accessible` and naturally
|
||||||
|
aligned for a pointer value.
|
||||||
|
|
||||||
|
The ``reserved_reg`` option is not yet implemented.
|
||||||
|
|
||||||
Heap examples
|
Heap examples
|
||||||
~~~~~~~~~~~~~
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
@@ -1144,19 +1154,11 @@ Glossary
|
|||||||
The extended basic blocks which contain all the executable code in a
|
The extended basic blocks which contain all the executable code in a
|
||||||
function. The function body follows the function preamble.
|
function. The function body follows the function preamble.
|
||||||
|
|
||||||
intermediate language
|
|
||||||
IL
|
|
||||||
The language used to describe functions to Cretonne. This reference
|
|
||||||
describes the syntax and semantics of the Cretonne IL. The IL has two
|
|
||||||
forms: Textual and an in-memory intermediate representation
|
|
||||||
(:term:`IR`).
|
|
||||||
|
|
||||||
intermediate representation
|
intermediate representation
|
||||||
IR
|
IR
|
||||||
The in-memory representation of :term:`IL`. The data structures
|
The language used to describe functions to Cretonne. This reference
|
||||||
Cretonne uses to represent a program internally are called the
|
describes the syntax and semantics of Cretonne IR. The IR has two
|
||||||
intermediate representation. Cretonne's IR can be converted to text
|
forms: Textual, and an in-memory data structure.
|
||||||
losslessly.
|
|
||||||
|
|
||||||
stack slot
|
stack slot
|
||||||
A fixed size memory allocation in the current function's activation
|
A fixed size memory allocation in the current function's activation
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ easier to provide substantial input functions for the compiler tests.
|
|||||||
|
|
||||||
File tests are :file:`*.cton` files in the :file:`filetests/` directory
|
File tests are :file:`*.cton` files in the :file:`filetests/` directory
|
||||||
hierarchy. Each file has a header describing what to test followed by a number
|
hierarchy. Each file has a header describing what to test followed by a number
|
||||||
of input functions in the :doc:`Cretonne textual intermediate language
|
of input functions in the :doc:`Cretonne textual intermediate representation
|
||||||
<langref>`:
|
<langref>`:
|
||||||
|
|
||||||
.. productionlist::
|
.. productionlist::
|
||||||
@@ -136,13 +136,15 @@ This example will run the legalizer test twice. Both runs will have
|
|||||||
``opt_level=best``, but they will have different ``is_64bit`` settings. The 32-bit
|
``opt_level=best``, but they will have different ``is_64bit`` settings. The 32-bit
|
||||||
run will also have the RISC-V specific flag ``supports_m`` disabled.
|
run will also have the RISC-V specific flag ``supports_m`` disabled.
|
||||||
|
|
||||||
|
The filetests are run automatically as part of `cargo test`, and they can
|
||||||
|
also be run manually with the `cton-util test` command.
|
||||||
|
|
||||||
Filecheck
|
Filecheck
|
||||||
---------
|
---------
|
||||||
|
|
||||||
Many of the test commands described below use *filecheck* to verify their
|
Many of the test commands described below use *filecheck* to verify their
|
||||||
output. Filecheck is a Rust implementation of the LLVM tool of the same name.
|
output. Filecheck is a Rust implementation of the LLVM tool of the same name.
|
||||||
See the :file:`lib/filecheck` `documentation <https://docs.rs/filecheck/>`_ for
|
See the `documentation <https://docs.rs/filecheck/>`_ for details of its syntax.
|
||||||
details of its syntax.
|
|
||||||
|
|
||||||
Comments in :file:`.cton` files are associated with the entity they follow.
|
Comments in :file:`.cton` files are associated with the entity they follow.
|
||||||
This typically means an instruction or the whole function. Those tests that
|
This typically means an instruction or the whole function. Those tests that
|
||||||
@@ -164,7 +166,7 @@ Cretonne's tests don't need this.
|
|||||||
----------
|
----------
|
||||||
|
|
||||||
This is one of the simplest file tests, used for testing the conversion to and
|
This is one of the simplest file tests, used for testing the conversion to and
|
||||||
from textual IL. The ``test cat`` command simply parses each function and
|
from textual IR. The ``test cat`` command simply parses each function and
|
||||||
converts it back to text again. The text of each function is then matched
|
converts it back to text again. The text of each function is then matched
|
||||||
against the associated filecheck directives.
|
against the associated filecheck directives.
|
||||||
|
|
||||||
@@ -186,7 +188,7 @@ Example::
|
|||||||
`test verifier`
|
`test verifier`
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
Run each function through the IL verifier and check that it produces the
|
Run each function through the IR verifier and check that it produces the
|
||||||
expected error messages.
|
expected error messages.
|
||||||
|
|
||||||
Expected error messages are indicated with an ``error:`` directive *on the
|
Expected error messages are indicated with an ``error:`` directive *on the
|
||||||
@@ -324,6 +326,38 @@ Test the simple GVN pass.
|
|||||||
The simple GVN pass is run on each function, and then results are run
|
The simple GVN pass is run on each function, and then results are run
|
||||||
through filecheck.
|
through filecheck.
|
||||||
|
|
||||||
|
`test licm`
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Test the LICM pass.
|
||||||
|
|
||||||
|
The LICM pass is run on each function, and then results are run
|
||||||
|
through filecheck.
|
||||||
|
|
||||||
|
`test dce`
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Test the DCE pass.
|
||||||
|
|
||||||
|
The DCE pass is run on each function, and then results are run
|
||||||
|
through filecheck.
|
||||||
|
|
||||||
|
`test preopt`
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Test the preopt pass.
|
||||||
|
|
||||||
|
The preopt pass is run on each function, and then results are run
|
||||||
|
through filecheck.
|
||||||
|
|
||||||
|
`test postopt`
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Test the postopt pass.
|
||||||
|
|
||||||
|
The postopt pass is run on each function, and then results are run
|
||||||
|
through filecheck.
|
||||||
|
|
||||||
`test compile`
|
`test compile`
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
@@ -333,4 +367,4 @@ Each function is passed through the full ``Context::compile()`` function
|
|||||||
which is normally used to compile code. This type of test often depends
|
which is normally used to compile code. This type of test often depends
|
||||||
on assertions or verifier errors, but it is also possible to use
|
on assertions or verifier errors, but it is also possible to use
|
||||||
filecheck directives which will be matched against the final form of the
|
filecheck directives which will be matched against the final form of the
|
||||||
Cretonne IL right before binary machine code emission.
|
Cretonne IR right before binary machine code emission.
|
||||||
|
|||||||
46
cranelift/filetests/dce/basic.cton
Normal file
46
cranelift/filetests/dce/basic.cton
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
test dce
|
||||||
|
|
||||||
|
function %simple() -> i32 {
|
||||||
|
ebb0:
|
||||||
|
v2 = iconst.i32 2
|
||||||
|
v3 = iconst.i32 3
|
||||||
|
return v3
|
||||||
|
}
|
||||||
|
; sameln: function %simple
|
||||||
|
; nextln: ebb0:
|
||||||
|
; nextln: v3 = iconst.i32 3
|
||||||
|
; nextln: return v3
|
||||||
|
; nextln: }
|
||||||
|
|
||||||
|
function %some_branching(i32, i32) -> i32 {
|
||||||
|
ebb0(v0: i32, v1: i32):
|
||||||
|
v3 = iconst.i32 70
|
||||||
|
v4 = iconst.i32 71
|
||||||
|
v5 = iconst.i32 72
|
||||||
|
v8 = iconst.i32 73
|
||||||
|
brz v0, ebb1
|
||||||
|
jump ebb2(v8)
|
||||||
|
|
||||||
|
ebb1:
|
||||||
|
v2 = iadd v0, v3
|
||||||
|
return v0
|
||||||
|
|
||||||
|
ebb2(v9: i32):
|
||||||
|
v6 = iadd v1, v4
|
||||||
|
v7 = iadd v6, v9
|
||||||
|
return v7
|
||||||
|
}
|
||||||
|
; sameln: function %some_branching
|
||||||
|
; nextln: ebb0(v0: i32, v1: i32):
|
||||||
|
; nextln: v4 = iconst.i32 71
|
||||||
|
; nextln: v8 = iconst.i32 73
|
||||||
|
; nextln: brz v0, ebb1
|
||||||
|
; nextln: jump ebb2(v8)
|
||||||
|
; nextln:
|
||||||
|
; nextln: ebb1:
|
||||||
|
; nextln: return v0
|
||||||
|
; nextln:
|
||||||
|
; nextln: ebb2(v9: i32):
|
||||||
|
; nextln: v6 = iadd.i32 v1, v4
|
||||||
|
; nextln: v7 = iadd v6, v9
|
||||||
|
; nextln: return v7
|
||||||
@@ -59,7 +59,7 @@ function %test(i32) {
|
|||||||
; nextln: ebb5:
|
; nextln: ebb5:
|
||||||
; nextln: }
|
; nextln: }
|
||||||
|
|
||||||
function %loop2(i32) native {
|
function %loop2(i32) system_v {
|
||||||
ebb0(v0: i32):
|
ebb0(v0: i32):
|
||||||
brz v0, ebb1 ; dominates: ebb1 ebb3 ebb4 ebb5
|
brz v0, ebb1 ; dominates: ebb1 ebb3 ebb4 ebb5
|
||||||
jump ebb2 ; dominates: ebb2
|
jump ebb2 ; dominates: ebb2
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ function %loop1(i32) {
|
|||||||
; nextln: ebb9:
|
; nextln: ebb9:
|
||||||
; nextln: }
|
; nextln: }
|
||||||
|
|
||||||
function %loop2(i32) native {
|
function %loop2(i32) system_v {
|
||||||
ebb0(v0: i32):
|
ebb0(v0: i32):
|
||||||
brz v0, ebb1 ; dominates: ebb1 ebb3 ebb4 ebb5
|
brz v0, ebb1 ; dominates: ebb1 ebb3 ebb4 ebb5
|
||||||
jump ebb2 ; dominates: ebb2
|
jump ebb2 ; dominates: ebb2
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ test compile
|
|||||||
set is_64bit=1
|
set is_64bit=1
|
||||||
isa intel haswell
|
isa intel haswell
|
||||||
|
|
||||||
function %foo(i64, i64, i64, i32) -> b1 native {
|
function %foo(i64, i64, i64, i32) -> b1 system_v {
|
||||||
ebb3(v0: i64, v1: i64, v2: i64, v3: i32):
|
ebb3(v0: i64, v1: i64, v2: i64, v3: i32):
|
||||||
v5 = icmp ne v2, v2
|
v5 = icmp ne v2, v2
|
||||||
v8 = iconst.i64 0
|
v8 = iconst.i64 0
|
||||||
|
|||||||
@@ -5,14 +5,14 @@ isa intel
|
|||||||
; regex: V=v\d+
|
; regex: V=v\d+
|
||||||
|
|
||||||
function %f() {
|
function %f() {
|
||||||
sig0 = (i32) -> i32 native
|
sig0 = (i32) -> i32 system_v
|
||||||
; check: sig0 = (i32 [0]) -> i32 [%rax] native
|
; check: sig0 = (i32 [0]) -> i32 [%rax] system_v
|
||||||
|
|
||||||
sig1 = (i64) -> b1 native
|
sig1 = (i64) -> b1 system_v
|
||||||
; check: sig1 = (i32 [0], i32 [4]) -> b1 [%rax] native
|
; check: sig1 = (i32 [0], i32 [4]) -> b1 [%rax] system_v
|
||||||
|
|
||||||
sig2 = (f32, i64) -> f64 native
|
sig2 = (f32, i64) -> f64 system_v
|
||||||
; check: sig2 = (f32 [0], i32 [4], i32 [8]) -> f64 [%xmm0] native
|
; check: sig2 = (f32 [0], i32 [4], i32 [8]) -> f64 [%xmm0] system_v
|
||||||
|
|
||||||
ebb0:
|
ebb0:
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -6,14 +6,14 @@ isa intel
|
|||||||
; regex: V=v\d+
|
; regex: V=v\d+
|
||||||
|
|
||||||
function %f() {
|
function %f() {
|
||||||
sig0 = (i32) -> i32 native
|
sig0 = (i32) -> i32 system_v
|
||||||
; check: sig0 = (i32 [%rdi]) -> i32 [%rax] native
|
; check: sig0 = (i32 [%rdi]) -> i32 [%rax] system_v
|
||||||
|
|
||||||
sig1 = (i64) -> b1 native
|
sig1 = (i64) -> b1 system_v
|
||||||
; check: sig1 = (i64 [%rdi]) -> b1 [%rax] native
|
; check: sig1 = (i64 [%rdi]) -> b1 [%rax] system_v
|
||||||
|
|
||||||
sig2 = (f32, i64) -> f64 native
|
sig2 = (f32, i64) -> f64 system_v
|
||||||
; check: sig2 = (f32 [%xmm0], i64 [%rdi]) -> f64 [%xmm0] native
|
; check: sig2 = (f32 [%xmm0], i64 [%rdi]) -> f64 [%xmm0] system_v
|
||||||
|
|
||||||
ebb0:
|
ebb0:
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -47,28 +47,23 @@ ebb1(v20: i32):
|
|||||||
function %i64_popcount(i64) -> i64 {
|
function %i64_popcount(i64) -> i64 {
|
||||||
ebb0(v30: i64):
|
ebb0(v30: i64):
|
||||||
v31 = popcnt v30;
|
v31 = popcnt v30;
|
||||||
; check: iconst.i32
|
; check: ushr_imm
|
||||||
; check: ushr
|
|
||||||
; check: iconst.i64
|
; check: iconst.i64
|
||||||
; check: band
|
; check: band
|
||||||
; check: isub
|
; check: isub
|
||||||
; check: iconst.i32
|
; check: ushr_imm
|
||||||
; check: ushr
|
|
||||||
; check: band
|
; check: band
|
||||||
; check: isub
|
; check: isub
|
||||||
; check: iconst.i32
|
; check: ushr_imm
|
||||||
; check: ushr
|
|
||||||
; check: band
|
; check: band
|
||||||
; check: isub
|
; check: isub
|
||||||
; check: iconst.i32
|
; check: ushr_imm
|
||||||
; check: ushr
|
|
||||||
; check: iadd
|
; check: iadd
|
||||||
; check: iconst.i64
|
; check: iconst.i64
|
||||||
; check: band
|
; check: band
|
||||||
; check: iconst.i64
|
; check: iconst.i64
|
||||||
; check: imul
|
; check: imul
|
||||||
; check: iconst.i32
|
; check: ushr_imm
|
||||||
; check: ushr
|
|
||||||
return v31;
|
return v31;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,27 +73,22 @@ ebb0(v30: i64):
|
|||||||
function %i32_popcount(i32) -> i32 {
|
function %i32_popcount(i32) -> i32 {
|
||||||
ebb0(v40: i32):
|
ebb0(v40: i32):
|
||||||
v41 = popcnt v40;
|
v41 = popcnt v40;
|
||||||
; check: iconst.i32
|
; check: ushr_imm
|
||||||
; check: ushr
|
|
||||||
; check: iconst.i32
|
; check: iconst.i32
|
||||||
; check: band
|
; check: band
|
||||||
; check: isub
|
; check: isub
|
||||||
; check: iconst.i32
|
; check: ushr_imm
|
||||||
; check: ushr
|
|
||||||
; check: band
|
; check: band
|
||||||
; check: isub
|
; check: isub
|
||||||
; check: iconst.i32
|
; check: ushr_imm
|
||||||
; check: ushr
|
|
||||||
; check: band
|
; check: band
|
||||||
; check: isub
|
; check: isub
|
||||||
; check: iconst.i32
|
; check: ushr_imm
|
||||||
; check: ushr
|
|
||||||
; check: iadd
|
; check: iadd
|
||||||
; check: iconst.i32
|
; check: iconst.i32
|
||||||
; check: band
|
; check: band
|
||||||
; check: iconst.i32
|
; check: iconst.i32
|
||||||
; check: imul
|
; check: imul
|
||||||
; check: iconst.i32
|
; check: ushr_imm
|
||||||
; check: ushr
|
|
||||||
return v41;
|
return v41;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,56 +15,56 @@ ebb0:
|
|||||||
|
|
||||||
[-,%r11] v10 = iconst.i64 0x1234
|
[-,%r11] v10 = iconst.i64 0x1234
|
||||||
; asm: bsfq %r11, %rcx
|
; asm: bsfq %r11, %rcx
|
||||||
[-,%rcx,%eflags] v11, v12 = x86_bsf v10 ; bin: 49 0f bc cb
|
[-,%rcx,%rflags] v11, v12 = x86_bsf v10 ; bin: 49 0f bc cb
|
||||||
|
|
||||||
[-,%rdx] v14 = iconst.i64 0x5678
|
[-,%rdx] v14 = iconst.i64 0x5678
|
||||||
; asm: bsfq %rdx, %r12
|
; asm: bsfq %rdx, %r12
|
||||||
[-,%r12,%eflags] v15, v16 = x86_bsf v14 ; bin: 4c 0f bc e2
|
[-,%r12,%rflags] v15, v16 = x86_bsf v14 ; bin: 4c 0f bc e2
|
||||||
|
|
||||||
; asm: bsfq %rdx, %rdi
|
; asm: bsfq %rdx, %rdi
|
||||||
[-,%rdi,%eflags] v17, v18 = x86_bsf v14 ; bin: 48 0f bc fa
|
[-,%rdi,%rflags] v17, v18 = x86_bsf v14 ; bin: 48 0f bc fa
|
||||||
|
|
||||||
|
|
||||||
; 32-bit wide bsf
|
; 32-bit wide bsf
|
||||||
|
|
||||||
[-,%r11] v20 = iconst.i32 0x1234
|
[-,%r11] v20 = iconst.i32 0x1234
|
||||||
; asm: bsfl %r11d, %ecx
|
; asm: bsfl %r11d, %ecx
|
||||||
[-,%rcx,%eflags] v21, v22 = x86_bsf v20 ; bin: 41 0f bc cb
|
[-,%rcx,%rflags] v21, v22 = x86_bsf v20 ; bin: 41 0f bc cb
|
||||||
|
|
||||||
[-,%rdx] v24 = iconst.i32 0x5678
|
[-,%rdx] v24 = iconst.i32 0x5678
|
||||||
; asm: bsfl %edx, %r12d
|
; asm: bsfl %edx, %r12d
|
||||||
[-,%r12,%eflags] v25, v26 = x86_bsf v24 ; bin: 44 0f bc e2
|
[-,%r12,%rflags] v25, v26 = x86_bsf v24 ; bin: 44 0f bc e2
|
||||||
|
|
||||||
; asm: bsfl %edx, %esi
|
; asm: bsfl %edx, %esi
|
||||||
[-,%rsi,%eflags] v27, v28 = x86_bsf v24 ; bin: 0f bc f2
|
[-,%rsi,%rflags] v27, v28 = x86_bsf v24 ; bin: 0f bc f2
|
||||||
|
|
||||||
|
|
||||||
; 64-bit wide bsr
|
; 64-bit wide bsr
|
||||||
|
|
||||||
[-,%r11] v30 = iconst.i64 0x1234
|
[-,%r11] v30 = iconst.i64 0x1234
|
||||||
; asm: bsrq %r11, %rcx
|
; asm: bsrq %r11, %rcx
|
||||||
[-,%rcx,%eflags] v31, v32 = x86_bsr v30 ; bin: 49 0f bd cb
|
[-,%rcx,%rflags] v31, v32 = x86_bsr v30 ; bin: 49 0f bd cb
|
||||||
|
|
||||||
[-,%rdx] v34 = iconst.i64 0x5678
|
[-,%rdx] v34 = iconst.i64 0x5678
|
||||||
; asm: bsrq %rdx, %r12
|
; asm: bsrq %rdx, %r12
|
||||||
[-,%r12,%eflags] v35, v36 = x86_bsr v34 ; bin: 4c 0f bd e2
|
[-,%r12,%rflags] v35, v36 = x86_bsr v34 ; bin: 4c 0f bd e2
|
||||||
|
|
||||||
; asm: bsrq %rdx, %rdi
|
; asm: bsrq %rdx, %rdi
|
||||||
[-,%rdi,%eflags] v37, v38 = x86_bsr v34 ; bin: 48 0f bd fa
|
[-,%rdi,%rflags] v37, v38 = x86_bsr v34 ; bin: 48 0f bd fa
|
||||||
|
|
||||||
|
|
||||||
; 32-bit wide bsr
|
; 32-bit wide bsr
|
||||||
|
|
||||||
[-,%r11] v40 = iconst.i32 0x1234
|
[-,%r11] v40 = iconst.i32 0x1234
|
||||||
; asm: bsrl %r11d, %ecx
|
; asm: bsrl %r11d, %ecx
|
||||||
[-,%rcx,%eflags] v41, v42 = x86_bsr v40 ; bin: 41 0f bd cb
|
[-,%rcx,%rflags] v41, v42 = x86_bsr v40 ; bin: 41 0f bd cb
|
||||||
|
|
||||||
[-,%rdx] v44 = iconst.i32 0x5678
|
[-,%rdx] v44 = iconst.i32 0x5678
|
||||||
; asm: bsrl %edx, %r12d
|
; asm: bsrl %edx, %r12d
|
||||||
[-,%r12,%eflags] v45, v46 = x86_bsr v44 ; bin: 44 0f bd e2
|
[-,%r12,%rflags] v45, v46 = x86_bsr v44 ; bin: 44 0f bd e2
|
||||||
|
|
||||||
; asm: bsrl %edx, %esi
|
; asm: bsrl %edx, %esi
|
||||||
[-,%rsi,%eflags] v47, v48 = x86_bsr v44 ; bin: 0f bd f2
|
[-,%rsi,%rflags] v47, v48 = x86_bsr v44 ; bin: 0f bd f2
|
||||||
|
|
||||||
|
|
||||||
; 64-bit wide cmov
|
; 64-bit wide cmov
|
||||||
|
|||||||
@@ -147,48 +147,48 @@ ebb0:
|
|||||||
|
|
||||||
; Load/Store
|
; Load/Store
|
||||||
|
|
||||||
; asm: movd (%ecx), %xmm5
|
; asm: movss (%ecx), %xmm5
|
||||||
[-,%xmm5] v100 = load.f32 v0 ; bin: 66 0f 6e 29
|
[-,%xmm5] v100 = load.f32 v0 ; bin: heap_oob f3 0f 10 29
|
||||||
; asm: movd (%esi), %xmm2
|
; asm: movss (%esi), %xmm2
|
||||||
[-,%xmm2] v101 = load.f32 v1 ; bin: 66 0f 6e 16
|
[-,%xmm2] v101 = load.f32 v1 ; bin: heap_oob f3 0f 10 16
|
||||||
; asm: movd 50(%ecx), %xmm5
|
; asm: movss 50(%ecx), %xmm5
|
||||||
[-,%xmm5] v110 = load.f32 v0+50 ; bin: 66 0f 6e 69 32
|
[-,%xmm5] v110 = load.f32 v0+50 ; bin: heap_oob f3 0f 10 69 32
|
||||||
; asm: movd -50(%esi), %xmm2
|
; asm: movss -50(%esi), %xmm2
|
||||||
[-,%xmm2] v111 = load.f32 v1-50 ; bin: 66 0f 6e 56 ce
|
[-,%xmm2] v111 = load.f32 v1-50 ; bin: heap_oob f3 0f 10 56 ce
|
||||||
; asm: movd 10000(%ecx), %xmm5
|
; asm: movss 10000(%ecx), %xmm5
|
||||||
[-,%xmm5] v120 = load.f32 v0+10000 ; bin: 66 0f 6e a9 00002710
|
[-,%xmm5] v120 = load.f32 v0+10000 ; bin: heap_oob f3 0f 10 a9 00002710
|
||||||
; asm: movd -10000(%esi), %xmm2
|
; asm: movss -10000(%esi), %xmm2
|
||||||
[-,%xmm2] v121 = load.f32 v1-10000 ; bin: 66 0f 6e 96 ffffd8f0
|
[-,%xmm2] v121 = load.f32 v1-10000 ; bin: heap_oob f3 0f 10 96 ffffd8f0
|
||||||
|
|
||||||
; asm: movd %xmm5, (%ecx)
|
; asm: movss %xmm5, (%ecx)
|
||||||
[-] store.f32 v100, v0 ; bin: 66 0f 7e 29
|
[-] store.f32 v100, v0 ; bin: heap_oob f3 0f 11 29
|
||||||
; asm: movd %xmm2, (%esi)
|
; asm: movss %xmm2, (%esi)
|
||||||
[-] store.f32 v101, v1 ; bin: 66 0f 7e 16
|
[-] store.f32 v101, v1 ; bin: heap_oob f3 0f 11 16
|
||||||
; asm: movd %xmm5, 50(%ecx)
|
; asm: movss %xmm5, 50(%ecx)
|
||||||
[-] store.f32 v100, v0+50 ; bin: 66 0f 7e 69 32
|
[-] store.f32 v100, v0+50 ; bin: heap_oob f3 0f 11 69 32
|
||||||
; asm: movd %xmm2, -50(%esi)
|
; asm: movss %xmm2, -50(%esi)
|
||||||
[-] store.f32 v101, v1-50 ; bin: 66 0f 7e 56 ce
|
[-] store.f32 v101, v1-50 ; bin: heap_oob f3 0f 11 56 ce
|
||||||
; asm: movd %xmm5, 10000(%ecx)
|
; asm: movss %xmm5, 10000(%ecx)
|
||||||
[-] store.f32 v100, v0+10000 ; bin: 66 0f 7e a9 00002710
|
[-] store.f32 v100, v0+10000 ; bin: heap_oob f3 0f 11 a9 00002710
|
||||||
; asm: movd %xmm2, -10000(%esi)
|
; asm: movss %xmm2, -10000(%esi)
|
||||||
[-] store.f32 v101, v1-10000 ; bin: 66 0f 7e 96 ffffd8f0
|
[-] store.f32 v101, v1-10000 ; bin: heap_oob f3 0f 11 96 ffffd8f0
|
||||||
|
|
||||||
; Spill / Fill.
|
; Spill / Fill.
|
||||||
|
|
||||||
; asm: movd %xmm5, 1032(%esp)
|
; asm: movss %xmm5, 1032(%esp)
|
||||||
[-,ss1] v200 = spill v100 ; bin: 66 0f 7e ac 24 00000408
|
[-,ss1] v200 = spill v100 ; bin: f3 0f 11 ac 24 00000408
|
||||||
; asm: movd %xmm2, 1032(%esp)
|
; asm: movss %xmm2, 1032(%esp)
|
||||||
[-,ss1] v201 = spill v101 ; bin: 66 0f 7e 94 24 00000408
|
[-,ss1] v201 = spill v101 ; bin: f3 0f 11 94 24 00000408
|
||||||
|
|
||||||
; asm: movd 1032(%esp), %xmm5
|
; asm: movss 1032(%esp), %xmm5
|
||||||
[-,%xmm5] v210 = fill v200 ; bin: 66 0f 6e ac 24 00000408
|
[-,%xmm5] v210 = fill v200 ; bin: f3 0f 10 ac 24 00000408
|
||||||
; asm: movd 1032(%esp), %xmm2
|
; asm: movss 1032(%esp), %xmm2
|
||||||
[-,%xmm2] v211 = fill v201 ; bin: 66 0f 6e 94 24 00000408
|
[-,%xmm2] v211 = fill v201 ; bin: f3 0f 10 94 24 00000408
|
||||||
|
|
||||||
; asm: movd %xmm5, 1032(%rsp)
|
; asm: movss %xmm5, 1032(%rsp)
|
||||||
regspill v100, %xmm5 -> ss1 ; bin: 66 0f 7e ac 24 00000408
|
regspill v100, %xmm5 -> ss1 ; bin: f3 0f 11 ac 24 00000408
|
||||||
; asm: movd 1032(%rsp), %xmm5
|
; asm: movss 1032(%rsp), %xmm5
|
||||||
regfill v100, ss1 -> %xmm5 ; bin: 66 0f 6e ac 24 00000408
|
regfill v100, ss1 -> %xmm5 ; bin: f3 0f 10 ac 24 00000408
|
||||||
|
|
||||||
; Comparisons.
|
; Comparisons.
|
||||||
;
|
;
|
||||||
@@ -221,11 +221,11 @@ ebb0:
|
|||||||
[-,%rdx] v307 = fcmp ule v11, v10 ; bin: 0f 2e d5 0f 96 c2
|
[-,%rdx] v307 = fcmp ule v11, v10 ; bin: 0f 2e d5 0f 96 c2
|
||||||
|
|
||||||
; asm: ucomiss %xmm2, %xmm5
|
; asm: ucomiss %xmm2, %xmm5
|
||||||
[-,%eflags] v310 = ffcmp v10, v11 ; bin: 0f 2e ea
|
[-,%rflags] v310 = ffcmp v10, v11 ; bin: 0f 2e ea
|
||||||
; asm: ucomiss %xmm2, %xmm5
|
; asm: ucomiss %xmm2, %xmm5
|
||||||
[-,%eflags] v311 = ffcmp v11, v10 ; bin: 0f 2e d5
|
[-,%rflags] v311 = ffcmp v11, v10 ; bin: 0f 2e d5
|
||||||
; asm: ucomiss %xmm5, %xmm5
|
; asm: ucomiss %xmm5, %xmm5
|
||||||
[-,%eflags] v312 = ffcmp v10, v10 ; bin: 0f 2e ed
|
[-,%rflags] v312 = ffcmp v10, v10 ; bin: 0f 2e ed
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -362,48 +362,48 @@ ebb0:
|
|||||||
|
|
||||||
; Load/Store
|
; Load/Store
|
||||||
|
|
||||||
; asm: movq (%ecx), %xmm5
|
; asm: movsd (%ecx), %xmm5
|
||||||
[-,%xmm5] v100 = load.f64 v0 ; bin: f3 0f 7e 29
|
[-,%xmm5] v100 = load.f64 v0 ; bin: heap_oob f2 0f 10 29
|
||||||
; asm: movq (%esi), %xmm2
|
; asm: movsd (%esi), %xmm2
|
||||||
[-,%xmm2] v101 = load.f64 v1 ; bin: f3 0f 7e 16
|
[-,%xmm2] v101 = load.f64 v1 ; bin: heap_oob f2 0f 10 16
|
||||||
; asm: movq 50(%ecx), %xmm5
|
; asm: movsd 50(%ecx), %xmm5
|
||||||
[-,%xmm5] v110 = load.f64 v0+50 ; bin: f3 0f 7e 69 32
|
[-,%xmm5] v110 = load.f64 v0+50 ; bin: heap_oob f2 0f 10 69 32
|
||||||
; asm: movq -50(%esi), %xmm2
|
; asm: movsd -50(%esi), %xmm2
|
||||||
[-,%xmm2] v111 = load.f64 v1-50 ; bin: f3 0f 7e 56 ce
|
[-,%xmm2] v111 = load.f64 v1-50 ; bin: heap_oob f2 0f 10 56 ce
|
||||||
; asm: movq 10000(%ecx), %xmm5
|
; asm: movsd 10000(%ecx), %xmm5
|
||||||
[-,%xmm5] v120 = load.f64 v0+10000 ; bin: f3 0f 7e a9 00002710
|
[-,%xmm5] v120 = load.f64 v0+10000 ; bin: heap_oob f2 0f 10 a9 00002710
|
||||||
; asm: movq -10000(%esi), %xmm2
|
; asm: movsd -10000(%esi), %xmm2
|
||||||
[-,%xmm2] v121 = load.f64 v1-10000 ; bin: f3 0f 7e 96 ffffd8f0
|
[-,%xmm2] v121 = load.f64 v1-10000 ; bin: heap_oob f2 0f 10 96 ffffd8f0
|
||||||
|
|
||||||
; asm: movq %xmm5, (%ecx)
|
; asm: movsd %xmm5, (%ecx)
|
||||||
[-] store.f64 v100, v0 ; bin: 66 0f d6 29
|
[-] store.f64 v100, v0 ; bin: heap_oob f2 0f 11 29
|
||||||
; asm: movq %xmm2, (%esi)
|
; asm: movsd %xmm2, (%esi)
|
||||||
[-] store.f64 v101, v1 ; bin: 66 0f d6 16
|
[-] store.f64 v101, v1 ; bin: heap_oob f2 0f 11 16
|
||||||
; asm: movq %xmm5, 50(%ecx)
|
; asm: movsd %xmm5, 50(%ecx)
|
||||||
[-] store.f64 v100, v0+50 ; bin: 66 0f d6 69 32
|
[-] store.f64 v100, v0+50 ; bin: heap_oob f2 0f 11 69 32
|
||||||
; asm: movq %xmm2, -50(%esi)
|
; asm: movsd %xmm2, -50(%esi)
|
||||||
[-] store.f64 v101, v1-50 ; bin: 66 0f d6 56 ce
|
[-] store.f64 v101, v1-50 ; bin: heap_oob f2 0f 11 56 ce
|
||||||
; asm: movq %xmm5, 10000(%ecx)
|
; asm: movsd %xmm5, 10000(%ecx)
|
||||||
[-] store.f64 v100, v0+10000 ; bin: 66 0f d6 a9 00002710
|
[-] store.f64 v100, v0+10000 ; bin: heap_oob f2 0f 11 a9 00002710
|
||||||
; asm: movq %xmm2, -10000(%esi)
|
; asm: movsd %xmm2, -10000(%esi)
|
||||||
[-] store.f64 v101, v1-10000 ; bin: 66 0f d6 96 ffffd8f0
|
[-] store.f64 v101, v1-10000 ; bin: heap_oob f2 0f 11 96 ffffd8f0
|
||||||
|
|
||||||
; Spill / Fill.
|
; Spill / Fill.
|
||||||
|
|
||||||
; asm: movq %xmm5, 1032(%esp)
|
; asm: movsd %xmm5, 1032(%esp)
|
||||||
[-,ss1] v200 = spill v100 ; bin: 66 0f d6 ac 24 00000408
|
[-,ss1] v200 = spill v100 ; bin: f2 0f 11 ac 24 00000408
|
||||||
; asm: movq %xmm2, 1032(%esp)
|
; asm: movsd %xmm2, 1032(%esp)
|
||||||
[-,ss1] v201 = spill v101 ; bin: 66 0f d6 94 24 00000408
|
[-,ss1] v201 = spill v101 ; bin: f2 0f 11 94 24 00000408
|
||||||
|
|
||||||
; asm: movq 1032(%esp), %xmm5
|
; asm: movsd 1032(%esp), %xmm5
|
||||||
[-,%xmm5] v210 = fill v200 ; bin: f3 0f 7e ac 24 00000408
|
[-,%xmm5] v210 = fill v200 ; bin: f2 0f 10 ac 24 00000408
|
||||||
; asm: movq 1032(%esp), %xmm2
|
; asm: movsd 1032(%esp), %xmm2
|
||||||
[-,%xmm2] v211 = fill v201 ; bin: f3 0f 7e 94 24 00000408
|
[-,%xmm2] v211 = fill v201 ; bin: f2 0f 10 94 24 00000408
|
||||||
|
|
||||||
; asm: movq %xmm5, 1032(%rsp)
|
; asm: movsd %xmm5, 1032(%rsp)
|
||||||
regspill v100, %xmm5 -> ss1 ; bin: 66 0f d6 ac 24 00000408
|
regspill v100, %xmm5 -> ss1 ; bin: f2 0f 11 ac 24 00000408
|
||||||
; asm: movq 1032(%rsp), %xmm5
|
; asm: movsd 1032(%rsp), %xmm5
|
||||||
regfill v100, ss1 -> %xmm5 ; bin: f3 0f 7e ac 24 00000408
|
regfill v100, ss1 -> %xmm5 ; bin: f2 0f 10 ac 24 00000408
|
||||||
|
|
||||||
; Comparisons.
|
; Comparisons.
|
||||||
;
|
;
|
||||||
@@ -436,11 +436,11 @@ ebb0:
|
|||||||
[-,%rdx] v307 = fcmp ule v11, v10 ; bin: 66 0f 2e d5 0f 96 c2
|
[-,%rdx] v307 = fcmp ule v11, v10 ; bin: 66 0f 2e d5 0f 96 c2
|
||||||
|
|
||||||
; asm: ucomisd %xmm2, %xmm5
|
; asm: ucomisd %xmm2, %xmm5
|
||||||
[-,%eflags] v310 = ffcmp v10, v11 ; bin: 66 0f 2e ea
|
[-,%rflags] v310 = ffcmp v10, v11 ; bin: 66 0f 2e ea
|
||||||
; asm: ucomisd %xmm2, %xmm5
|
; asm: ucomisd %xmm2, %xmm5
|
||||||
[-,%eflags] v311 = ffcmp v11, v10 ; bin: 66 0f 2e d5
|
[-,%rflags] v311 = ffcmp v11, v10 ; bin: 66 0f 2e d5
|
||||||
; asm: ucomisd %xmm5, %xmm5
|
; asm: ucomisd %xmm5, %xmm5
|
||||||
[-,%eflags] v312 = ffcmp v10, v10 ; bin: 66 0f 2e ed
|
[-,%rflags] v312 = ffcmp v10, v10 ; bin: 66 0f 2e ed
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -448,7 +448,7 @@ ebb0:
|
|||||||
function %cpuflags_float(f32 [%xmm0]) {
|
function %cpuflags_float(f32 [%xmm0]) {
|
||||||
ebb0(v0: f32 [%xmm0]):
|
ebb0(v0: f32 [%xmm0]):
|
||||||
; asm: ucomiss %xmm0, %xmm0
|
; asm: ucomiss %xmm0, %xmm0
|
||||||
[-,%eflags] v1 = ffcmp v0, v0 ; bin: 0f 2e c0
|
[-,%rflags] v1 = ffcmp v0, v0 ; bin: 0f 2e c0
|
||||||
|
|
||||||
jump ebb1
|
jump ebb1
|
||||||
|
|
||||||
@@ -471,21 +471,21 @@ ebb1:
|
|||||||
brff ule v1, ebb1 ; bin: 76 f0
|
brff ule v1, ebb1 ; bin: 76 f0
|
||||||
|
|
||||||
; asm: jp .+4; ud2
|
; asm: jp .+4; ud2
|
||||||
trapff ord v1, user0 ; bin: 7a 02 0f 0b
|
trapff ord v1, user0 ; bin: 7a 02 user0 0f 0b
|
||||||
; asm: jnp .+4; ud2
|
; asm: jnp .+4; ud2
|
||||||
trapff uno v1, user0 ; bin: 7b 02 0f 0b
|
trapff uno v1, user0 ; bin: 7b 02 user0 0f 0b
|
||||||
; asm: je .+4; ud2
|
; asm: je .+4; ud2
|
||||||
trapff one v1, user0 ; bin: 74 02 0f 0b
|
trapff one v1, user0 ; bin: 74 02 user0 0f 0b
|
||||||
; asm: jne .+4; ud2
|
; asm: jne .+4; ud2
|
||||||
trapff ueq v1, user0 ; bin: 75 02 0f 0b
|
trapff ueq v1, user0 ; bin: 75 02 user0 0f 0b
|
||||||
; asm: jna .+4; ud2
|
; asm: jna .+4; ud2
|
||||||
trapff gt v1, user0 ; bin: 76 02 0f 0b
|
trapff gt v1, user0 ; bin: 76 02 user0 0f 0b
|
||||||
; asm: jnae .+4; ud2
|
; asm: jnae .+4; ud2
|
||||||
trapff ge v1, user0 ; bin: 72 02 0f 0b
|
trapff ge v1, user0 ; bin: 72 02 user0 0f 0b
|
||||||
; asm: jnb .+4; ud2
|
; asm: jnb .+4; ud2
|
||||||
trapff ult v1, user0 ; bin: 73 02 0f 0b
|
trapff ult v1, user0 ; bin: 73 02 user0 0f 0b
|
||||||
; asm: jnbe .+4; ud2
|
; asm: jnbe .+4; ud2
|
||||||
trapff ule v1, user0 ; bin: 77 02 0f 0b
|
trapff ule v1, user0 ; bin: 77 02 user0 0f 0b
|
||||||
|
|
||||||
; asm: setnp %bl
|
; asm: setnp %bl
|
||||||
[-,%rbx] v10 = trueff ord v1 ; bin: 0f 9b c3
|
[-,%rbx] v10 = trueff ord v1 ; bin: 0f 9b c3
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
; binary emission of 32-bit code.
|
; binary emission of x86-32 code.
|
||||||
test binemit
|
test binemit
|
||||||
set is_compressed
|
set is_compressed
|
||||||
isa intel haswell
|
isa intel haswell
|
||||||
@@ -25,6 +25,9 @@ ebb0:
|
|||||||
; asm: movl $2, %esi
|
; asm: movl $2, %esi
|
||||||
[-,%rsi] v2 = iconst.i32 2 ; bin: be 00000002
|
[-,%rsi] v2 = iconst.i32 2 ; bin: be 00000002
|
||||||
|
|
||||||
|
; asm: movb $1, %cl
|
||||||
|
[-,%rcx] v9007 = bconst.b1 true ; bin: b9 00000001
|
||||||
|
|
||||||
; Integer Register-Register Operations.
|
; Integer Register-Register Operations.
|
||||||
|
|
||||||
; asm: addl %esi, %ecx
|
; asm: addl %esi, %ecx
|
||||||
@@ -125,13 +128,13 @@ ebb0:
|
|||||||
; asm: movl $2, %edx
|
; asm: movl $2, %edx
|
||||||
[-,%rdx] v53 = iconst.i32 2 ; bin: ba 00000002
|
[-,%rdx] v53 = iconst.i32 2 ; bin: ba 00000002
|
||||||
; asm: idivl %ecx
|
; asm: idivl %ecx
|
||||||
[-,%rax,%rdx] v54, v55 = x86_sdivmodx v52, v53, v1 ; bin: f7 f9
|
[-,%rax,%rdx] v54, v55 = x86_sdivmodx v52, v53, v1 ; bin: int_divz f7 f9
|
||||||
; asm: idivl %esi
|
; asm: idivl %esi
|
||||||
[-,%rax,%rdx] v56, v57 = x86_sdivmodx v52, v53, v2 ; bin: f7 fe
|
[-,%rax,%rdx] v56, v57 = x86_sdivmodx v52, v53, v2 ; bin: int_divz f7 fe
|
||||||
; asm: divl %ecx
|
; asm: divl %ecx
|
||||||
[-,%rax,%rdx] v58, v59 = x86_udivmodx v52, v53, v1 ; bin: f7 f1
|
[-,%rax,%rdx] v58, v59 = x86_udivmodx v52, v53, v1 ; bin: int_divz f7 f1
|
||||||
; asm: divl %esi
|
; asm: divl %esi
|
||||||
[-,%rax,%rdx] v60, v61 = x86_udivmodx v52, v53, v2 ; bin: f7 f6
|
[-,%rax,%rdx] v60, v61 = x86_udivmodx v52, v53, v2 ; bin: int_divz f7 f6
|
||||||
|
|
||||||
; Register copies.
|
; Register copies.
|
||||||
|
|
||||||
@@ -152,105 +155,105 @@ ebb0:
|
|||||||
; Register indirect addressing with no displacement.
|
; Register indirect addressing with no displacement.
|
||||||
|
|
||||||
; asm: movl %ecx, (%esi)
|
; asm: movl %ecx, (%esi)
|
||||||
store v1, v2 ; bin: 89 0e
|
store v1, v2 ; bin: heap_oob 89 0e
|
||||||
; asm: movl %esi, (%ecx)
|
; asm: movl %esi, (%ecx)
|
||||||
store v2, v1 ; bin: 89 31
|
store v2, v1 ; bin: heap_oob 89 31
|
||||||
; asm: movw %cx, (%esi)
|
; asm: movw %cx, (%esi)
|
||||||
istore16 v1, v2 ; bin: 66 89 0e
|
istore16 v1, v2 ; bin: heap_oob 66 89 0e
|
||||||
; asm: movw %si, (%ecx)
|
; asm: movw %si, (%ecx)
|
||||||
istore16 v2, v1 ; bin: 66 89 31
|
istore16 v2, v1 ; bin: heap_oob 66 89 31
|
||||||
; asm: movb %cl, (%esi)
|
; asm: movb %cl, (%esi)
|
||||||
istore8 v1, v2 ; bin: 88 0e
|
istore8 v1, v2 ; bin: heap_oob 88 0e
|
||||||
; Can't store %sil in 32-bit mode (needs REX prefix).
|
; Can't store %sil in 32-bit mode (needs REX prefix).
|
||||||
|
|
||||||
; asm: movl (%ecx), %edi
|
; asm: movl (%ecx), %edi
|
||||||
[-,%rdi] v100 = load.i32 v1 ; bin: 8b 39
|
[-,%rdi] v100 = load.i32 v1 ; bin: heap_oob 8b 39
|
||||||
; asm: movl (%esi), %edx
|
; asm: movl (%esi), %edx
|
||||||
[-,%rdx] v101 = load.i32 v2 ; bin: 8b 16
|
[-,%rdx] v101 = load.i32 v2 ; bin: heap_oob 8b 16
|
||||||
; asm: movzwl (%ecx), %edi
|
; asm: movzwl (%ecx), %edi
|
||||||
[-,%rdi] v102 = uload16.i32 v1 ; bin: 0f b7 39
|
[-,%rdi] v102 = uload16.i32 v1 ; bin: heap_oob 0f b7 39
|
||||||
; asm: movzwl (%esi), %edx
|
; asm: movzwl (%esi), %edx
|
||||||
[-,%rdx] v103 = uload16.i32 v2 ; bin: 0f b7 16
|
[-,%rdx] v103 = uload16.i32 v2 ; bin: heap_oob 0f b7 16
|
||||||
; asm: movswl (%ecx), %edi
|
; asm: movswl (%ecx), %edi
|
||||||
[-,%rdi] v104 = sload16.i32 v1 ; bin: 0f bf 39
|
[-,%rdi] v104 = sload16.i32 v1 ; bin: heap_oob 0f bf 39
|
||||||
; asm: movswl (%esi), %edx
|
; asm: movswl (%esi), %edx
|
||||||
[-,%rdx] v105 = sload16.i32 v2 ; bin: 0f bf 16
|
[-,%rdx] v105 = sload16.i32 v2 ; bin: heap_oob 0f bf 16
|
||||||
; asm: movzbl (%ecx), %edi
|
; asm: movzbl (%ecx), %edi
|
||||||
[-,%rdi] v106 = uload8.i32 v1 ; bin: 0f b6 39
|
[-,%rdi] v106 = uload8.i32 v1 ; bin: heap_oob 0f b6 39
|
||||||
; asm: movzbl (%esi), %edx
|
; asm: movzbl (%esi), %edx
|
||||||
[-,%rdx] v107 = uload8.i32 v2 ; bin: 0f b6 16
|
[-,%rdx] v107 = uload8.i32 v2 ; bin: heap_oob 0f b6 16
|
||||||
; asm: movsbl (%ecx), %edi
|
; asm: movsbl (%ecx), %edi
|
||||||
[-,%rdi] v108 = sload8.i32 v1 ; bin: 0f be 39
|
[-,%rdi] v108 = sload8.i32 v1 ; bin: heap_oob 0f be 39
|
||||||
; asm: movsbl (%esi), %edx
|
; asm: movsbl (%esi), %edx
|
||||||
[-,%rdx] v109 = sload8.i32 v2 ; bin: 0f be 16
|
[-,%rdx] v109 = sload8.i32 v2 ; bin: heap_oob 0f be 16
|
||||||
|
|
||||||
; Register-indirect with 8-bit signed displacement.
|
; Register-indirect with 8-bit signed displacement.
|
||||||
|
|
||||||
; asm: movl %ecx, 100(%esi)
|
; asm: movl %ecx, 100(%esi)
|
||||||
store v1, v2+100 ; bin: 89 4e 64
|
store v1, v2+100 ; bin: heap_oob 89 4e 64
|
||||||
; asm: movl %esi, -100(%ecx)
|
; asm: movl %esi, -100(%ecx)
|
||||||
store v2, v1-100 ; bin: 89 71 9c
|
store v2, v1-100 ; bin: heap_oob 89 71 9c
|
||||||
; asm: movw %cx, 100(%esi)
|
; asm: movw %cx, 100(%esi)
|
||||||
istore16 v1, v2+100 ; bin: 66 89 4e 64
|
istore16 v1, v2+100 ; bin: heap_oob 66 89 4e 64
|
||||||
; asm: movw %si, -100(%ecx)
|
; asm: movw %si, -100(%ecx)
|
||||||
istore16 v2, v1-100 ; bin: 66 89 71 9c
|
istore16 v2, v1-100 ; bin: heap_oob 66 89 71 9c
|
||||||
; asm: movb %cl, 100(%esi)
|
; asm: movb %cl, 100(%esi)
|
||||||
istore8 v1, v2+100 ; bin: 88 4e 64
|
istore8 v1, v2+100 ; bin: heap_oob 88 4e 64
|
||||||
|
|
||||||
; asm: movl 50(%ecx), %edi
|
; asm: movl 50(%ecx), %edi
|
||||||
[-,%rdi] v110 = load.i32 v1+50 ; bin: 8b 79 32
|
[-,%rdi] v110 = load.i32 v1+50 ; bin: heap_oob 8b 79 32
|
||||||
; asm: movl -50(%esi), %edx
|
; asm: movl -50(%esi), %edx
|
||||||
[-,%rdx] v111 = load.i32 v2-50 ; bin: 8b 56 ce
|
[-,%rdx] v111 = load.i32 v2-50 ; bin: heap_oob 8b 56 ce
|
||||||
; asm: movzwl 50(%ecx), %edi
|
; asm: movzwl 50(%ecx), %edi
|
||||||
[-,%rdi] v112 = uload16.i32 v1+50 ; bin: 0f b7 79 32
|
[-,%rdi] v112 = uload16.i32 v1+50 ; bin: heap_oob 0f b7 79 32
|
||||||
; asm: movzwl -50(%esi), %edx
|
; asm: movzwl -50(%esi), %edx
|
||||||
[-,%rdx] v113 = uload16.i32 v2-50 ; bin: 0f b7 56 ce
|
[-,%rdx] v113 = uload16.i32 v2-50 ; bin: heap_oob 0f b7 56 ce
|
||||||
; asm: movswl 50(%ecx), %edi
|
; asm: movswl 50(%ecx), %edi
|
||||||
[-,%rdi] v114 = sload16.i32 v1+50 ; bin: 0f bf 79 32
|
[-,%rdi] v114 = sload16.i32 v1+50 ; bin: heap_oob 0f bf 79 32
|
||||||
; asm: movswl -50(%esi), %edx
|
; asm: movswl -50(%esi), %edx
|
||||||
[-,%rdx] v115 = sload16.i32 v2-50 ; bin: 0f bf 56 ce
|
[-,%rdx] v115 = sload16.i32 v2-50 ; bin: heap_oob 0f bf 56 ce
|
||||||
; asm: movzbl 50(%ecx), %edi
|
; asm: movzbl 50(%ecx), %edi
|
||||||
[-,%rdi] v116 = uload8.i32 v1+50 ; bin: 0f b6 79 32
|
[-,%rdi] v116 = uload8.i32 v1+50 ; bin: heap_oob 0f b6 79 32
|
||||||
; asm: movzbl -50(%esi), %edx
|
; asm: movzbl -50(%esi), %edx
|
||||||
[-,%rdx] v117 = uload8.i32 v2-50 ; bin: 0f b6 56 ce
|
[-,%rdx] v117 = uload8.i32 v2-50 ; bin: heap_oob 0f b6 56 ce
|
||||||
; asm: movsbl 50(%ecx), %edi
|
; asm: movsbl 50(%ecx), %edi
|
||||||
[-,%rdi] v118 = sload8.i32 v1+50 ; bin: 0f be 79 32
|
[-,%rdi] v118 = sload8.i32 v1+50 ; bin: heap_oob 0f be 79 32
|
||||||
; asm: movsbl -50(%esi), %edx
|
; asm: movsbl -50(%esi), %edx
|
||||||
[-,%rdx] v119 = sload8.i32 v2-50 ; bin: 0f be 56 ce
|
[-,%rdx] v119 = sload8.i32 v2-50 ; bin: heap_oob 0f be 56 ce
|
||||||
|
|
||||||
; Register-indirect with 32-bit signed displacement.
|
; Register-indirect with 32-bit signed displacement.
|
||||||
|
|
||||||
; asm: movl %ecx, 10000(%esi)
|
; asm: movl %ecx, 10000(%esi)
|
||||||
store v1, v2+10000 ; bin: 89 8e 00002710
|
store v1, v2+10000 ; bin: heap_oob 89 8e 00002710
|
||||||
; asm: movl %esi, -10000(%ecx)
|
; asm: movl %esi, -10000(%ecx)
|
||||||
store v2, v1-10000 ; bin: 89 b1 ffffd8f0
|
store v2, v1-10000 ; bin: heap_oob 89 b1 ffffd8f0
|
||||||
; asm: movw %cx, 10000(%esi)
|
; asm: movw %cx, 10000(%esi)
|
||||||
istore16 v1, v2+10000 ; bin: 66 89 8e 00002710
|
istore16 v1, v2+10000 ; bin: heap_oob 66 89 8e 00002710
|
||||||
; asm: movw %si, -10000(%ecx)
|
; asm: movw %si, -10000(%ecx)
|
||||||
istore16 v2, v1-10000 ; bin: 66 89 b1 ffffd8f0
|
istore16 v2, v1-10000 ; bin: heap_oob 66 89 b1 ffffd8f0
|
||||||
; asm: movb %cl, 10000(%esi)
|
; asm: movb %cl, 10000(%esi)
|
||||||
istore8 v1, v2+10000 ; bin: 88 8e 00002710
|
istore8 v1, v2+10000 ; bin: heap_oob 88 8e 00002710
|
||||||
|
|
||||||
; asm: movl 50000(%ecx), %edi
|
; asm: movl 50000(%ecx), %edi
|
||||||
[-,%rdi] v120 = load.i32 v1+50000 ; bin: 8b b9 0000c350
|
[-,%rdi] v120 = load.i32 v1+50000 ; bin: heap_oob 8b b9 0000c350
|
||||||
; asm: movl -50000(%esi), %edx
|
; asm: movl -50000(%esi), %edx
|
||||||
[-,%rdx] v121 = load.i32 v2-50000 ; bin: 8b 96 ffff3cb0
|
[-,%rdx] v121 = load.i32 v2-50000 ; bin: heap_oob 8b 96 ffff3cb0
|
||||||
; asm: movzwl 50000(%ecx), %edi
|
; asm: movzwl 50000(%ecx), %edi
|
||||||
[-,%rdi] v122 = uload16.i32 v1+50000 ; bin: 0f b7 b9 0000c350
|
[-,%rdi] v122 = uload16.i32 v1+50000 ; bin: heap_oob 0f b7 b9 0000c350
|
||||||
; asm: movzwl -50000(%esi), %edx
|
; asm: movzwl -50000(%esi), %edx
|
||||||
[-,%rdx] v123 = uload16.i32 v2-50000 ; bin: 0f b7 96 ffff3cb0
|
[-,%rdx] v123 = uload16.i32 v2-50000 ; bin: heap_oob 0f b7 96 ffff3cb0
|
||||||
; asm: movswl 50000(%ecx), %edi
|
; asm: movswl 50000(%ecx), %edi
|
||||||
[-,%rdi] v124 = sload16.i32 v1+50000 ; bin: 0f bf b9 0000c350
|
[-,%rdi] v124 = sload16.i32 v1+50000 ; bin: heap_oob 0f bf b9 0000c350
|
||||||
; asm: movswl -50000(%esi), %edx
|
; asm: movswl -50000(%esi), %edx
|
||||||
[-,%rdx] v125 = sload16.i32 v2-50000 ; bin: 0f bf 96 ffff3cb0
|
[-,%rdx] v125 = sload16.i32 v2-50000 ; bin: heap_oob 0f bf 96 ffff3cb0
|
||||||
; asm: movzbl 50000(%ecx), %edi
|
; asm: movzbl 50000(%ecx), %edi
|
||||||
[-,%rdi] v126 = uload8.i32 v1+50000 ; bin: 0f b6 b9 0000c350
|
[-,%rdi] v126 = uload8.i32 v1+50000 ; bin: heap_oob 0f b6 b9 0000c350
|
||||||
; asm: movzbl -50000(%esi), %edx
|
; asm: movzbl -50000(%esi), %edx
|
||||||
[-,%rdx] v127 = uload8.i32 v2-50000 ; bin: 0f b6 96 ffff3cb0
|
[-,%rdx] v127 = uload8.i32 v2-50000 ; bin: heap_oob 0f b6 96 ffff3cb0
|
||||||
; asm: movsbl 50000(%ecx), %edi
|
; asm: movsbl 50000(%ecx), %edi
|
||||||
[-,%rdi] v128 = sload8.i32 v1+50000 ; bin: 0f be b9 0000c350
|
[-,%rdi] v128 = sload8.i32 v1+50000 ; bin: heap_oob 0f be b9 0000c350
|
||||||
; asm: movsbl -50000(%esi), %edx
|
; asm: movsbl -50000(%esi), %edx
|
||||||
[-,%rdx] v129 = sload8.i32 v2-50000 ; bin: 0f be 96 ffff3cb0
|
[-,%rdx] v129 = sload8.i32 v2-50000 ; bin: heap_oob 0f be 96 ffff3cb0
|
||||||
|
|
||||||
; Bit-counting instructions.
|
; Bit-counting instructions.
|
||||||
|
|
||||||
@@ -403,6 +406,13 @@ ebb0:
|
|||||||
; asm: addl $-2147483648, %esp
|
; asm: addl $-2147483648, %esp
|
||||||
adjust_sp_imm -2147483648 ; bin: 81 c4 80000000
|
adjust_sp_imm -2147483648 ; bin: 81 c4 80000000
|
||||||
|
|
||||||
|
; Shift immediates
|
||||||
|
; asm: shll $2, %esi
|
||||||
|
[-,%rsi] v513 = ishl_imm v2, 2 ; bin: c1 e6 02
|
||||||
|
; asm: sarl $5, %esi
|
||||||
|
[-,%rsi] v514 = sshr_imm v2, 5 ; bin: c1 fe 05
|
||||||
|
; asm: shrl $8, %esi
|
||||||
|
[-,%rsi] v515 = ushr_imm v2, 8 ; bin: c1 ee 08
|
||||||
|
|
||||||
; asm: testl %ecx, %ecx
|
; asm: testl %ecx, %ecx
|
||||||
; asm: je ebb1
|
; asm: je ebb1
|
||||||
@@ -427,7 +437,7 @@ ebb1:
|
|||||||
|
|
||||||
; asm: ebb2:
|
; asm: ebb2:
|
||||||
ebb2:
|
ebb2:
|
||||||
trap user0 ; bin: 0f 0b
|
trap user0 ; bin: user0 0f 0b
|
||||||
}
|
}
|
||||||
|
|
||||||
; Special branch encodings only for I32 mode.
|
; Special branch encodings only for I32 mode.
|
||||||
@@ -466,9 +476,9 @@ ebb0:
|
|||||||
|
|
||||||
ebb1:
|
ebb1:
|
||||||
; asm: cmpl %esi, %ecx
|
; asm: cmpl %esi, %ecx
|
||||||
[-,%eflags] v10 = ifcmp v1, v2 ; bin: 39 f1
|
[-,%rflags] v10 = ifcmp v1, v2 ; bin: 39 f1
|
||||||
; asm: cmpl %ecx, %esi
|
; asm: cmpl %ecx, %esi
|
||||||
[-,%eflags] v11 = ifcmp v2, v1 ; bin: 39 ce
|
[-,%rflags] v11 = ifcmp v2, v1 ; bin: 39 ce
|
||||||
|
|
||||||
; asm: je ebb1
|
; asm: je ebb1
|
||||||
brif eq v11, ebb1 ; bin: 74 fa
|
brif eq v11, ebb1 ; bin: 74 fa
|
||||||
@@ -514,41 +524,41 @@ ebb1:
|
|||||||
|
|
||||||
; The trapif instructions are encoded as macros: a conditional jump over a ud2.
|
; The trapif instructions are encoded as macros: a conditional jump over a ud2.
|
||||||
; asm: jne .+4; ud2
|
; asm: jne .+4; ud2
|
||||||
trapif eq v11, user0 ; bin: 75 02 0f 0b
|
trapif eq v11, user0 ; bin: 75 02 user0 0f 0b
|
||||||
; asm: je .+4; ud2
|
; asm: je .+4; ud2
|
||||||
trapif ne v11, user0 ; bin: 74 02 0f 0b
|
trapif ne v11, user0 ; bin: 74 02 user0 0f 0b
|
||||||
; asm: jnl .+4; ud2
|
; asm: jnl .+4; ud2
|
||||||
trapif slt v11, user0 ; bin: 7d 02 0f 0b
|
trapif slt v11, user0 ; bin: 7d 02 user0 0f 0b
|
||||||
; asm: jnge .+4; ud2
|
; asm: jnge .+4; ud2
|
||||||
trapif sge v11, user0 ; bin: 7c 02 0f 0b
|
trapif sge v11, user0 ; bin: 7c 02 user0 0f 0b
|
||||||
; asm: jng .+4; ud2
|
; asm: jng .+4; ud2
|
||||||
trapif sgt v11, user0 ; bin: 7e 02 0f 0b
|
trapif sgt v11, user0 ; bin: 7e 02 user0 0f 0b
|
||||||
; asm: jnle .+4; ud2
|
; asm: jnle .+4; ud2
|
||||||
trapif sle v11, user0 ; bin: 7f 02 0f 0b
|
trapif sle v11, user0 ; bin: 7f 02 user0 0f 0b
|
||||||
; asm: jnb .+4; ud2
|
; asm: jnb .+4; ud2
|
||||||
trapif ult v11, user0 ; bin: 73 02 0f 0b
|
trapif ult v11, user0 ; bin: 73 02 user0 0f 0b
|
||||||
; asm: jnae .+4; ud2
|
; asm: jnae .+4; ud2
|
||||||
trapif uge v11, user0 ; bin: 72 02 0f 0b
|
trapif uge v11, user0 ; bin: 72 02 user0 0f 0b
|
||||||
; asm: jna .+4; ud2
|
; asm: jna .+4; ud2
|
||||||
trapif ugt v11, user0 ; bin: 76 02 0f 0b
|
trapif ugt v11, user0 ; bin: 76 02 user0 0f 0b
|
||||||
; asm: jnbe .+4; ud2
|
; asm: jnbe .+4; ud2
|
||||||
trapif ule v11, user0 ; bin: 77 02 0f 0b
|
trapif ule v11, user0 ; bin: 77 02 user0 0f 0b
|
||||||
|
|
||||||
; Stack check.
|
; Stack check.
|
||||||
; asm: cmpl %esp, %ecx
|
; asm: cmpl %esp, %ecx
|
||||||
[-,%eflags] v40 = ifcmp_sp v1 ; bin: 39 e1
|
[-,%rflags] v40 = ifcmp_sp v1 ; bin: 39 e1
|
||||||
; asm: cmpl %esp, %esi
|
; asm: cmpl %esp, %esi
|
||||||
[-,%eflags] v41 = ifcmp_sp v2 ; bin: 39 e6
|
[-,%rflags] v41 = ifcmp_sp v2 ; bin: 39 e6
|
||||||
|
|
||||||
; asm: cmpl $-100, %ecx
|
; asm: cmpl $-100, %ecx
|
||||||
[-,%eflags] v42 = ifcmp_imm v1, -100 ; bin: 83 f9 9c
|
[-,%rflags] v42 = ifcmp_imm v1, -100 ; bin: 83 f9 9c
|
||||||
; asm: cmpl $100, %esi
|
; asm: cmpl $100, %esi
|
||||||
[-,%eflags] v43 = ifcmp_imm v2, 100 ; bin: 83 fe 64
|
[-,%rflags] v43 = ifcmp_imm v2, 100 ; bin: 83 fe 64
|
||||||
|
|
||||||
; asm: cmpl $-10000, %ecx
|
; asm: cmpl $-10000, %ecx
|
||||||
[-,%eflags] v44 = ifcmp_imm v1, -10000 ; bin: 81 f9 ffffd8f0
|
[-,%rflags] v44 = ifcmp_imm v1, -10000 ; bin: 81 f9 ffffd8f0
|
||||||
; asm: cmpl $10000, %esi
|
; asm: cmpl $10000, %esi
|
||||||
[-,%eflags] v45 = ifcmp_imm v2, 10000 ; bin: 81 fe 00002710
|
[-,%rflags] v45 = ifcmp_imm v2, 10000 ; bin: 81 fe 00002710
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -566,7 +576,7 @@ ebb0:
|
|||||||
; asm: movzbl %cl, %esi
|
; asm: movzbl %cl, %esi
|
||||||
[-,%rsi] v30 = uextend.i32 v11 ; bin: 0f b6 f1
|
[-,%rsi] v30 = uextend.i32 v11 ; bin: 0f b6 f1
|
||||||
|
|
||||||
trap user0 ; bin: 0f 0b
|
trap user0 ; bin: user0 0f 0b
|
||||||
}
|
}
|
||||||
|
|
||||||
; Tests for i32/i16 conversion instructions.
|
; Tests for i32/i16 conversion instructions.
|
||||||
@@ -582,5 +592,5 @@ ebb0:
|
|||||||
; asm: movzwl %cx, %esi
|
; asm: movzwl %cx, %esi
|
||||||
[-,%rsi] v30 = uextend.i32 v11 ; bin: 0f b7 f1
|
[-,%rsi] v30 = uextend.i32 v11 ; bin: 0f b7 f1
|
||||||
|
|
||||||
trap user0 ; bin: 0f 0b
|
trap user0 ; bin: user0 0f 0b
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -157,52 +157,52 @@ ebb0:
|
|||||||
|
|
||||||
; Load/Store
|
; Load/Store
|
||||||
|
|
||||||
; asm: movd (%r14), %xmm5
|
; asm: movss (%r14), %xmm5
|
||||||
[-,%xmm5] v100 = load.f32 v3 ; bin: 66 41 0f 6e 2e
|
[-,%xmm5] v100 = load.f32 v3 ; bin: heap_oob f3 41 0f 10 2e
|
||||||
; asm: movd (%rax), %xmm10
|
; asm: movss (%rax), %xmm10
|
||||||
[-,%xmm10] v101 = load.f32 v2 ; bin: 66 44 0f 6e 10
|
[-,%xmm10] v101 = load.f32 v2 ; bin: heap_oob f3 44 0f 10 10
|
||||||
; asm: movd 50(%r14), %xmm5
|
; asm: movss 50(%r14), %xmm5
|
||||||
[-,%xmm5] v110 = load.f32 v3+50 ; bin: 66 41 0f 6e 6e 32
|
[-,%xmm5] v110 = load.f32 v3+50 ; bin: heap_oob f3 41 0f 10 6e 32
|
||||||
; asm: movd -50(%rax), %xmm10
|
; asm: movss -50(%rax), %xmm10
|
||||||
[-,%xmm10] v111 = load.f32 v2-50 ; bin: 66 44 0f 6e 50 ce
|
[-,%xmm10] v111 = load.f32 v2-50 ; bin: heap_oob f3 44 0f 10 50 ce
|
||||||
; asm: movd 10000(%r14), %xmm5
|
; asm: movss 10000(%r14), %xmm5
|
||||||
[-,%xmm5] v120 = load.f32 v3+10000 ; bin: 66 41 0f 6e ae 00002710
|
[-,%xmm5] v120 = load.f32 v3+10000 ; bin: heap_oob f3 41 0f 10 ae 00002710
|
||||||
; asm: movd -10000(%rax), %xmm10
|
; asm: movss -10000(%rax), %xmm10
|
||||||
[-,%xmm10] v121 = load.f32 v2-10000 ; bin: 66 44 0f 6e 90 ffffd8f0
|
[-,%xmm10] v121 = load.f32 v2-10000 ; bin: heap_oob f3 44 0f 10 90 ffffd8f0
|
||||||
|
|
||||||
; asm: movd %xmm5, (%r14)
|
; asm: movss %xmm5, (%r14)
|
||||||
[-] store.f32 v100, v3 ; bin: 66 41 0f 7e 2e
|
[-] store.f32 v100, v3 ; bin: heap_oob f3 41 0f 11 2e
|
||||||
; asm: movd %xmm10, (%rax)
|
; asm: movss %xmm10, (%rax)
|
||||||
[-] store.f32 v101, v2 ; bin: 66 44 0f 7e 10
|
[-] store.f32 v101, v2 ; bin: heap_oob f3 44 0f 11 10
|
||||||
; asm: movd %xmm5, (%r13)
|
; asm: movss %xmm5, (%r13)
|
||||||
[-] store.f32 v100, v4 ; bin: 66 41 0f 7e 6d 00
|
[-] store.f32 v100, v4 ; bin: heap_oob f3 41 0f 11 6d 00
|
||||||
; asm: movd %xmm10, (%r13)
|
; asm: movss %xmm10, (%r13)
|
||||||
[-] store.f32 v101, v4 ; bin: 66 45 0f 7e 55 00
|
[-] store.f32 v101, v4 ; bin: heap_oob f3 45 0f 11 55 00
|
||||||
; asm: movd %xmm5, 50(%r14)
|
; asm: movss %xmm5, 50(%r14)
|
||||||
[-] store.f32 v100, v3+50 ; bin: 66 41 0f 7e 6e 32
|
[-] store.f32 v100, v3+50 ; bin: heap_oob f3 41 0f 11 6e 32
|
||||||
; asm: movd %xmm10, -50(%rax)
|
; asm: movss %xmm10, -50(%rax)
|
||||||
[-] store.f32 v101, v2-50 ; bin: 66 44 0f 7e 50 ce
|
[-] store.f32 v101, v2-50 ; bin: heap_oob f3 44 0f 11 50 ce
|
||||||
; asm: movd %xmm5, 10000(%r14)
|
; asm: movss %xmm5, 10000(%r14)
|
||||||
[-] store.f32 v100, v3+10000 ; bin: 66 41 0f 7e ae 00002710
|
[-] store.f32 v100, v3+10000 ; bin: heap_oob f3 41 0f 11 ae 00002710
|
||||||
; asm: movd %xmm10, -10000(%rax)
|
; asm: movss %xmm10, -10000(%rax)
|
||||||
[-] store.f32 v101, v2-10000 ; bin: 66 44 0f 7e 90 ffffd8f0
|
[-] store.f32 v101, v2-10000 ; bin: heap_oob f3 44 0f 11 90 ffffd8f0
|
||||||
|
|
||||||
; Spill / Fill.
|
; Spill / Fill.
|
||||||
|
|
||||||
; asm: movd %xmm5, 1032(%rsp)
|
; asm: movss %xmm5, 1032(%rsp)
|
||||||
[-,ss1] v200 = spill v100 ; bin: 66 0f 7e ac 24 00000408
|
[-,ss1] v200 = spill v100 ; bin: f3 0f 11 ac 24 00000408
|
||||||
; asm: movd %xmm10, 1032(%rsp)
|
; asm: movss %xmm10, 1032(%rsp)
|
||||||
[-,ss1] v201 = spill v101 ; bin: 66 44 0f 7e 94 24 00000408
|
[-,ss1] v201 = spill v101 ; bin: f3 44 0f 11 94 24 00000408
|
||||||
|
|
||||||
; asm: movd 1032(%rsp), %xmm5
|
; asm: movss 1032(%rsp), %xmm5
|
||||||
[-,%xmm5] v210 = fill v200 ; bin: 66 0f 6e ac 24 00000408
|
[-,%xmm5] v210 = fill v200 ; bin: f3 0f 10 ac 24 00000408
|
||||||
; asm: movd 1032(%rsp), %xmm10
|
; asm: movss 1032(%rsp), %xmm10
|
||||||
[-,%xmm10] v211 = fill v201 ; bin: 66 44 0f 6e 94 24 00000408
|
[-,%xmm10] v211 = fill v201 ; bin: f3 44 0f 10 94 24 00000408
|
||||||
|
|
||||||
; asm: movd %xmm5, 1032(%rsp)
|
; asm: movss %xmm5, 1032(%rsp)
|
||||||
regspill v100, %xmm5 -> ss1 ; bin: 66 0f 7e ac 24 00000408
|
regspill v100, %xmm5 -> ss1 ; bin: f3 0f 11 ac 24 00000408
|
||||||
; asm: movd 1032(%rsp), %xmm5
|
; asm: movss 1032(%rsp), %xmm5
|
||||||
regfill v100, ss1 -> %xmm5 ; bin: 66 0f 6e ac 24 00000408
|
regfill v100, ss1 -> %xmm5 ; bin: f3 0f 10 ac 24 00000408
|
||||||
|
|
||||||
; Comparisons.
|
; Comparisons.
|
||||||
;
|
;
|
||||||
@@ -235,11 +235,11 @@ ebb0:
|
|||||||
[-,%rdx] v307 = fcmp ule v11, v10 ; bin: 44 0f 2e d5 0f 96 c2
|
[-,%rdx] v307 = fcmp ule v11, v10 ; bin: 44 0f 2e d5 0f 96 c2
|
||||||
|
|
||||||
; asm: ucomiss %xmm10, %xmm5
|
; asm: ucomiss %xmm10, %xmm5
|
||||||
[-,%eflags] v310 = ffcmp v10, v11 ; bin: 41 0f 2e ea
|
[-,%rflags] v310 = ffcmp v10, v11 ; bin: 41 0f 2e ea
|
||||||
; asm: ucomiss %xmm10, %xmm5
|
; asm: ucomiss %xmm10, %xmm5
|
||||||
[-,%eflags] v311 = ffcmp v11, v10 ; bin: 44 0f 2e d5
|
[-,%rflags] v311 = ffcmp v11, v10 ; bin: 44 0f 2e d5
|
||||||
; asm: ucomiss %xmm5, %xmm5
|
; asm: ucomiss %xmm5, %xmm5
|
||||||
[-,%eflags] v312 = ffcmp v10, v10 ; bin: 0f 2e ed
|
[-,%rflags] v312 = ffcmp v10, v10 ; bin: 0f 2e ed
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -392,52 +392,52 @@ ebb0:
|
|||||||
|
|
||||||
; Load/Store
|
; Load/Store
|
||||||
|
|
||||||
; asm: movq (%r14), %xmm5
|
; asm: movsd (%r14), %xmm5
|
||||||
[-,%xmm5] v100 = load.f64 v3 ; bin: f3 41 0f 7e 2e
|
[-,%xmm5] v100 = load.f64 v3 ; bin: heap_oob f2 41 0f 10 2e
|
||||||
; asm: movq (%rax), %xmm10
|
; asm: movsd (%rax), %xmm10
|
||||||
[-,%xmm10] v101 = load.f64 v2 ; bin: f3 44 0f 7e 10
|
[-,%xmm10] v101 = load.f64 v2 ; bin: heap_oob f2 44 0f 10 10
|
||||||
; asm: movq 50(%r14), %xmm5
|
; asm: movsd 50(%r14), %xmm5
|
||||||
[-,%xmm5] v110 = load.f64 v3+50 ; bin: f3 41 0f 7e 6e 32
|
[-,%xmm5] v110 = load.f64 v3+50 ; bin: heap_oob f2 41 0f 10 6e 32
|
||||||
; asm: movq -50(%rax), %xmm10
|
; asm: movsd -50(%rax), %xmm10
|
||||||
[-,%xmm10] v111 = load.f64 v2-50 ; bin: f3 44 0f 7e 50 ce
|
[-,%xmm10] v111 = load.f64 v2-50 ; bin: heap_oob f2 44 0f 10 50 ce
|
||||||
; asm: movq 10000(%r14), %xmm5
|
; asm: movsd 10000(%r14), %xmm5
|
||||||
[-,%xmm5] v120 = load.f64 v3+10000 ; bin: f3 41 0f 7e ae 00002710
|
[-,%xmm5] v120 = load.f64 v3+10000 ; bin: heap_oob f2 41 0f 10 ae 00002710
|
||||||
; asm: movq -10000(%rax), %xmm10
|
; asm: movsd -10000(%rax), %xmm10
|
||||||
[-,%xmm10] v121 = load.f64 v2-10000 ; bin: f3 44 0f 7e 90 ffffd8f0
|
[-,%xmm10] v121 = load.f64 v2-10000 ; bin: heap_oob f2 44 0f 10 90 ffffd8f0
|
||||||
|
|
||||||
; asm: movq %xmm5, (%r14)
|
; asm: movsd %xmm5, (%r14)
|
||||||
[-] store.f64 v100, v3 ; bin: 66 41 0f d6 2e
|
[-] store.f64 v100, v3 ; bin: heap_oob f2 41 0f 11 2e
|
||||||
; asm: movq %xmm10, (%rax)
|
; asm: movsd %xmm10, (%rax)
|
||||||
[-] store.f64 v101, v2 ; bin: 66 44 0f d6 10
|
[-] store.f64 v101, v2 ; bin: heap_oob f2 44 0f 11 10
|
||||||
; asm: movq %xmm5, (%r13)
|
; asm: movsd %xmm5, (%r13)
|
||||||
[-] store.f64 v100, v4 ; bin: 66 41 0f d6 6d 00
|
[-] store.f64 v100, v4 ; bin: heap_oob f2 41 0f 11 6d 00
|
||||||
; asm: movq %xmm10, (%r13)
|
; asm: movsd %xmm10, (%r13)
|
||||||
[-] store.f64 v101, v4 ; bin: 66 45 0f d6 55 00
|
[-] store.f64 v101, v4 ; bin: heap_oob f2 45 0f 11 55 00
|
||||||
; asm: movq %xmm5, 50(%r14)
|
; asm: movsd %xmm5, 50(%r14)
|
||||||
[-] store.f64 v100, v3+50 ; bin: 66 41 0f d6 6e 32
|
[-] store.f64 v100, v3+50 ; bin: heap_oob f2 41 0f 11 6e 32
|
||||||
; asm: movq %xmm10, -50(%rax)
|
; asm: movsd %xmm10, -50(%rax)
|
||||||
[-] store.f64 v101, v2-50 ; bin: 66 44 0f d6 50 ce
|
[-] store.f64 v101, v2-50 ; bin: heap_oob f2 44 0f 11 50 ce
|
||||||
; asm: movq %xmm5, 10000(%r14)
|
; asm: movsd %xmm5, 10000(%r14)
|
||||||
[-] store.f64 v100, v3+10000 ; bin: 66 41 0f d6 ae 00002710
|
[-] store.f64 v100, v3+10000 ; bin: heap_oob f2 41 0f 11 ae 00002710
|
||||||
; asm: movq %xmm10, -10000(%rax)
|
; asm: movsd %xmm10, -10000(%rax)
|
||||||
[-] store.f64 v101, v2-10000 ; bin: 66 44 0f d6 90 ffffd8f0
|
[-] store.f64 v101, v2-10000 ; bin: heap_oob f2 44 0f 11 90 ffffd8f0
|
||||||
|
|
||||||
; Spill / Fill.
|
; Spill / Fill.
|
||||||
|
|
||||||
; asm: movq %xmm5, 1032(%rsp)
|
; asm: movsd %xmm5, 1032(%rsp)
|
||||||
[-,ss1] v200 = spill v100 ; bin: 66 0f d6 ac 24 00000408
|
[-,ss1] v200 = spill v100 ; bin: f2 0f 11 ac 24 00000408
|
||||||
; asm: movq %xmm10, 1032(%rsp)
|
; asm: movsd %xmm10, 1032(%rsp)
|
||||||
[-,ss1] v201 = spill v101 ; bin: 66 44 0f d6 94 24 00000408
|
[-,ss1] v201 = spill v101 ; bin: f2 44 0f 11 94 24 00000408
|
||||||
|
|
||||||
; asm: movq 1032(%rsp), %xmm5
|
; asm: movsd 1032(%rsp), %xmm5
|
||||||
[-,%xmm5] v210 = fill v200 ; bin: f3 0f 7e ac 24 00000408
|
[-,%xmm5] v210 = fill v200 ; bin: f2 0f 10 ac 24 00000408
|
||||||
; asm: movq 1032(%rsp), %xmm10
|
; asm: movsd 1032(%rsp), %xmm10
|
||||||
[-,%xmm10] v211 = fill v201 ; bin: f3 44 0f 7e 94 24 00000408
|
[-,%xmm10] v211 = fill v201 ; bin: f2 44 0f 10 94 24 00000408
|
||||||
|
|
||||||
; asm: movq %xmm5, 1032(%rsp)
|
; asm: movsd %xmm5, 1032(%rsp)
|
||||||
regspill v100, %xmm5 -> ss1 ; bin: 66 0f d6 ac 24 00000408
|
regspill v100, %xmm5 -> ss1 ; bin: f2 0f 11 ac 24 00000408
|
||||||
; asm: movq 1032(%rsp), %xmm5
|
; asm: movsd 1032(%rsp), %xmm5
|
||||||
regfill v100, ss1 -> %xmm5 ; bin: f3 0f 7e ac 24 00000408
|
regfill v100, ss1 -> %xmm5 ; bin: f2 0f 10 ac 24 00000408
|
||||||
|
|
||||||
; Comparisons.
|
; Comparisons.
|
||||||
;
|
;
|
||||||
@@ -470,11 +470,11 @@ ebb0:
|
|||||||
[-,%rdx] v307 = fcmp ule v11, v10 ; bin: 66 44 0f 2e d5 0f 96 c2
|
[-,%rdx] v307 = fcmp ule v11, v10 ; bin: 66 44 0f 2e d5 0f 96 c2
|
||||||
|
|
||||||
; asm: ucomisd %xmm10, %xmm5
|
; asm: ucomisd %xmm10, %xmm5
|
||||||
[-,%eflags] v310 = ffcmp v10, v11 ; bin: 66 41 0f 2e ea
|
[-,%rflags] v310 = ffcmp v10, v11 ; bin: 66 41 0f 2e ea
|
||||||
; asm: ucomisd %xmm10, %xmm5
|
; asm: ucomisd %xmm10, %xmm5
|
||||||
[-,%eflags] v311 = ffcmp v11, v10 ; bin: 66 44 0f 2e d5
|
[-,%rflags] v311 = ffcmp v11, v10 ; bin: 66 44 0f 2e d5
|
||||||
; asm: ucomisd %xmm5, %xmm5
|
; asm: ucomisd %xmm5, %xmm5
|
||||||
[-,%eflags] v312 = ffcmp v10, v10 ; bin: 66 0f 2e ed
|
[-,%rflags] v312 = ffcmp v10, v10 ; bin: 66 0f 2e ed
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -482,7 +482,7 @@ ebb0:
|
|||||||
function %cpuflags_float(f32 [%xmm0]) {
|
function %cpuflags_float(f32 [%xmm0]) {
|
||||||
ebb0(v0: f32 [%xmm0]):
|
ebb0(v0: f32 [%xmm0]):
|
||||||
; asm: ucomiss %xmm0, %xmm0
|
; asm: ucomiss %xmm0, %xmm0
|
||||||
[-,%eflags] v1 = ffcmp v0, v0 ; bin: 0f 2e c0
|
[-,%rflags] v1 = ffcmp v0, v0 ; bin: 0f 2e c0
|
||||||
|
|
||||||
jump ebb1
|
jump ebb1
|
||||||
|
|
||||||
@@ -505,21 +505,21 @@ ebb1:
|
|||||||
brff ule v1, ebb1 ; bin: 76 f0
|
brff ule v1, ebb1 ; bin: 76 f0
|
||||||
|
|
||||||
; asm: jp .+4; ud2
|
; asm: jp .+4; ud2
|
||||||
trapff ord v1, user0 ; bin: 7a 02 0f 0b
|
trapff ord v1, user0 ; bin: 7a 02 user0 0f 0b
|
||||||
; asm: jnp .+4; ud2
|
; asm: jnp .+4; ud2
|
||||||
trapff uno v1, user0 ; bin: 7b 02 0f 0b
|
trapff uno v1, user0 ; bin: 7b 02 user0 0f 0b
|
||||||
; asm: je .+4; ud2
|
; asm: je .+4; ud2
|
||||||
trapff one v1, user0 ; bin: 74 02 0f 0b
|
trapff one v1, user0 ; bin: 74 02 user0 0f 0b
|
||||||
; asm: jne .+4; ud2
|
; asm: jne .+4; ud2
|
||||||
trapff ueq v1, user0 ; bin: 75 02 0f 0b
|
trapff ueq v1, user0 ; bin: 75 02 user0 0f 0b
|
||||||
; asm: jna .+4; ud2
|
; asm: jna .+4; ud2
|
||||||
trapff gt v1, user0 ; bin: 76 02 0f 0b
|
trapff gt v1, user0 ; bin: 76 02 user0 0f 0b
|
||||||
; asm: jnae .+4; ud2
|
; asm: jnae .+4; ud2
|
||||||
trapff ge v1, user0 ; bin: 72 02 0f 0b
|
trapff ge v1, user0 ; bin: 72 02 user0 0f 0b
|
||||||
; asm: jnb .+4; ud2
|
; asm: jnb .+4; ud2
|
||||||
trapff ult v1, user0 ; bin: 73 02 0f 0b
|
trapff ult v1, user0 ; bin: 73 02 user0 0f 0b
|
||||||
; asm: jnbe .+4; ud2
|
; asm: jnbe .+4; ud2
|
||||||
trapff ule v1, user0 ; bin: 77 02 0f 0b
|
trapff ule v1, user0 ; bin: 77 02 user0 0f 0b
|
||||||
|
|
||||||
; asm: setnp %bl
|
; asm: setnp %bl
|
||||||
[-,%rbx] v10 = trueff ord v1 ; bin: 0f 9b c3
|
[-,%rbx] v10 = trueff ord v1 ; bin: 0f 9b c3
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
; binary emission of 64-bit code.
|
; binary emission of x86-64 code.
|
||||||
test binemit
|
test binemit
|
||||||
set is_64bit
|
set is_64bit
|
||||||
set is_compressed
|
set is_compressed
|
||||||
@@ -38,6 +38,11 @@ ebb0:
|
|||||||
; asm: movq $0xffffffff88001122, %r14 # 32-bit sign-extended constant.
|
; asm: movq $0xffffffff88001122, %r14 # 32-bit sign-extended constant.
|
||||||
[-,%r14] v5 = iconst.i64 0xffff_ffff_8800_1122 ; bin: 49 c7 c6 88001122
|
[-,%r14] v5 = iconst.i64 0xffff_ffff_8800_1122 ; bin: 49 c7 c6 88001122
|
||||||
|
|
||||||
|
; asm: movb $1, %cl
|
||||||
|
[-,%rcx] v9007 = bconst.b1 true ; bin: b9 00000001
|
||||||
|
; asm: movb $1, %sil
|
||||||
|
[-,%r10] v9008 = bconst.b1 true ; bin: 41 ba 00000001
|
||||||
|
|
||||||
; Integer Register-Register Operations.
|
; Integer Register-Register Operations.
|
||||||
|
|
||||||
; asm: addq %rsi, %rcx
|
; asm: addq %rsi, %rcx
|
||||||
@@ -170,146 +175,146 @@ ebb0:
|
|||||||
; Register indirect addressing with no displacement.
|
; Register indirect addressing with no displacement.
|
||||||
|
|
||||||
; asm: movq %rcx, (%r10)
|
; asm: movq %rcx, (%r10)
|
||||||
store v1, v3 ; bin: 49 89 0a
|
store v1, v3 ; bin: heap_oob 49 89 0a
|
||||||
; asm: movq %r10, (%rcx)
|
; asm: movq %r10, (%rcx)
|
||||||
store v3, v1 ; bin: 4c 89 11
|
store v3, v1 ; bin: heap_oob 4c 89 11
|
||||||
; asm: movl %ecx, (%r10)
|
; asm: movl %ecx, (%r10)
|
||||||
istore32 v1, v3 ; bin: 41 89 0a
|
istore32 v1, v3 ; bin: heap_oob 41 89 0a
|
||||||
; asm: movl %r10d, (%rcx)
|
; asm: movl %r10d, (%rcx)
|
||||||
istore32 v3, v1 ; bin: 44 89 11
|
istore32 v3, v1 ; bin: heap_oob 44 89 11
|
||||||
; asm: movw %cx, (%r10)
|
; asm: movw %cx, (%r10)
|
||||||
istore16 v1, v3 ; bin: 66 41 89 0a
|
istore16 v1, v3 ; bin: heap_oob 66 41 89 0a
|
||||||
; asm: movw %r10w, (%rcx)
|
; asm: movw %r10w, (%rcx)
|
||||||
istore16 v3, v1 ; bin: 66 44 89 11
|
istore16 v3, v1 ; bin: heap_oob 66 44 89 11
|
||||||
; asm: movb %cl, (%r10)
|
; asm: movb %cl, (%r10)
|
||||||
istore8 v1, v3 ; bin: 41 88 0a
|
istore8 v1, v3 ; bin: heap_oob 41 88 0a
|
||||||
; asm: movb %r10b, (%rcx)
|
; asm: movb %r10b, (%rcx)
|
||||||
istore8 v3, v1 ; bin: 44 88 11
|
istore8 v3, v1 ; bin: heap_oob 44 88 11
|
||||||
|
|
||||||
; asm: movq (%rcx), %r14
|
; asm: movq (%rcx), %r14
|
||||||
[-,%r14] v120 = load.i64 v1 ; bin: 4c 8b 31
|
[-,%r14] v120 = load.i64 v1 ; bin: heap_oob 4c 8b 31
|
||||||
; asm: movq (%r10), %rdx
|
; asm: movq (%r10), %rdx
|
||||||
[-,%rdx] v121 = load.i64 v3 ; bin: 49 8b 12
|
[-,%rdx] v121 = load.i64 v3 ; bin: heap_oob 49 8b 12
|
||||||
; asm: movl (%rcx), %r14d
|
; asm: movl (%rcx), %r14d
|
||||||
[-,%r14] v122 = uload32.i64 v1 ; bin: 44 8b 31
|
[-,%r14] v122 = uload32.i64 v1 ; bin: heap_oob 44 8b 31
|
||||||
; asm: movl (%r10), %edx
|
; asm: movl (%r10), %edx
|
||||||
[-,%rdx] v123 = uload32.i64 v3 ; bin: 41 8b 12
|
[-,%rdx] v123 = uload32.i64 v3 ; bin: heap_oob 41 8b 12
|
||||||
; asm: movslq (%rcx), %r14
|
; asm: movslq (%rcx), %r14
|
||||||
[-,%r14] v124 = sload32.i64 v1 ; bin: 4c 63 31
|
[-,%r14] v124 = sload32.i64 v1 ; bin: heap_oob 4c 63 31
|
||||||
; asm: movslq (%r10), %rdx
|
; asm: movslq (%r10), %rdx
|
||||||
[-,%rdx] v125 = sload32.i64 v3 ; bin: 49 63 12
|
[-,%rdx] v125 = sload32.i64 v3 ; bin: heap_oob 49 63 12
|
||||||
; asm: movzwq (%rcx), %r14
|
; asm: movzwq (%rcx), %r14
|
||||||
[-,%r14] v126 = uload16.i64 v1 ; bin: 4c 0f b7 31
|
[-,%r14] v126 = uload16.i64 v1 ; bin: heap_oob 4c 0f b7 31
|
||||||
; asm: movzwq (%r10), %rdx
|
; asm: movzwq (%r10), %rdx
|
||||||
[-,%rdx] v127 = uload16.i64 v3 ; bin: 49 0f b7 12
|
[-,%rdx] v127 = uload16.i64 v3 ; bin: heap_oob 49 0f b7 12
|
||||||
; asm: movswq (%rcx), %r14
|
; asm: movswq (%rcx), %r14
|
||||||
[-,%r14] v128 = sload16.i64 v1 ; bin: 4c 0f bf 31
|
[-,%r14] v128 = sload16.i64 v1 ; bin: heap_oob 4c 0f bf 31
|
||||||
; asm: movswq (%r10), %rdx
|
; asm: movswq (%r10), %rdx
|
||||||
[-,%rdx] v129 = sload16.i64 v3 ; bin: 49 0f bf 12
|
[-,%rdx] v129 = sload16.i64 v3 ; bin: heap_oob 49 0f bf 12
|
||||||
; asm: movzbq (%rcx), %r14
|
; asm: movzbq (%rcx), %r14
|
||||||
[-,%r14] v130 = uload8.i64 v1 ; bin: 4c 0f b6 31
|
[-,%r14] v130 = uload8.i64 v1 ; bin: heap_oob 4c 0f b6 31
|
||||||
; asm: movzbq (%r10), %rdx
|
; asm: movzbq (%r10), %rdx
|
||||||
[-,%rdx] v131 = uload8.i64 v3 ; bin: 49 0f b6 12
|
[-,%rdx] v131 = uload8.i64 v3 ; bin: heap_oob 49 0f b6 12
|
||||||
; asm: movsbq (%rcx), %r14
|
; asm: movsbq (%rcx), %r14
|
||||||
[-,%r14] v132 = sload8.i64 v1 ; bin: 4c 0f be 31
|
[-,%r14] v132 = sload8.i64 v1 ; bin: heap_oob 4c 0f be 31
|
||||||
; asm: movsbq (%r10), %rdx
|
; asm: movsbq (%r10), %rdx
|
||||||
[-,%rdx] v133 = sload8.i64 v3 ; bin: 49 0f be 12
|
[-,%rdx] v133 = sload8.i64 v3 ; bin: heap_oob 49 0f be 12
|
||||||
|
|
||||||
; Register-indirect with 8-bit signed displacement.
|
; Register-indirect with 8-bit signed displacement.
|
||||||
|
|
||||||
; asm: movq %rcx, 100(%r10)
|
; asm: movq %rcx, 100(%r10)
|
||||||
store v1, v3+100 ; bin: 49 89 4a 64
|
store v1, v3+100 ; bin: heap_oob 49 89 4a 64
|
||||||
; asm: movq %r10, -100(%rcx)
|
; asm: movq %r10, -100(%rcx)
|
||||||
store v3, v1-100 ; bin: 4c 89 51 9c
|
store v3, v1-100 ; bin: heap_oob 4c 89 51 9c
|
||||||
; asm: movl %ecx, 100(%r10)
|
; asm: movl %ecx, 100(%r10)
|
||||||
istore32 v1, v3+100 ; bin: 41 89 4a 64
|
istore32 v1, v3+100 ; bin: heap_oob 41 89 4a 64
|
||||||
; asm: movl %r10d, -100(%rcx)
|
; asm: movl %r10d, -100(%rcx)
|
||||||
istore32 v3, v1-100 ; bin: 44 89 51 9c
|
istore32 v3, v1-100 ; bin: heap_oob 44 89 51 9c
|
||||||
; asm: movw %cx, 100(%r10)
|
; asm: movw %cx, 100(%r10)
|
||||||
istore16 v1, v3+100 ; bin: 66 41 89 4a 64
|
istore16 v1, v3+100 ; bin: heap_oob 66 41 89 4a 64
|
||||||
; asm: movw %r10w, -100(%rcx)
|
; asm: movw %r10w, -100(%rcx)
|
||||||
istore16 v3, v1-100 ; bin: 66 44 89 51 9c
|
istore16 v3, v1-100 ; bin: heap_oob 66 44 89 51 9c
|
||||||
; asm: movb %cl, 100(%r10)
|
; asm: movb %cl, 100(%r10)
|
||||||
istore8 v1, v3+100 ; bin: 41 88 4a 64
|
istore8 v1, v3+100 ; bin: heap_oob 41 88 4a 64
|
||||||
; asm: movb %r10b, 100(%rcx)
|
; asm: movb %r10b, 100(%rcx)
|
||||||
istore8 v3, v1+100 ; bin: 44 88 51 64
|
istore8 v3, v1+100 ; bin: heap_oob 44 88 51 64
|
||||||
|
|
||||||
; asm: movq 50(%rcx), %r10
|
; asm: movq 50(%rcx), %r10
|
||||||
[-,%r10] v140 = load.i64 v1+50 ; bin: 4c 8b 51 32
|
[-,%r10] v140 = load.i64 v1+50 ; bin: heap_oob 4c 8b 51 32
|
||||||
; asm: movq -50(%r10), %rdx
|
; asm: movq -50(%r10), %rdx
|
||||||
[-,%rdx] v141 = load.i64 v3-50 ; bin: 49 8b 52 ce
|
[-,%rdx] v141 = load.i64 v3-50 ; bin: heap_oob 49 8b 52 ce
|
||||||
; asm: movl 50(%rcx), %edi
|
; asm: movl 50(%rcx), %edi
|
||||||
[-,%rdi] v142 = uload32.i64 v1+50 ; bin: 8b 79 32
|
[-,%rdi] v142 = uload32.i64 v1+50 ; bin: heap_oob 8b 79 32
|
||||||
; asm: movl -50(%rsi), %edx
|
; asm: movl -50(%rsi), %edx
|
||||||
[-,%rdx] v143 = uload32.i64 v2-50 ; bin: 8b 56 ce
|
[-,%rdx] v143 = uload32.i64 v2-50 ; bin: heap_oob 8b 56 ce
|
||||||
; asm: movslq 50(%rcx), %rdi
|
; asm: movslq 50(%rcx), %rdi
|
||||||
[-,%rdi] v144 = sload32.i64 v1+50 ; bin: 48 63 79 32
|
[-,%rdi] v144 = sload32.i64 v1+50 ; bin: heap_oob 48 63 79 32
|
||||||
; asm: movslq -50(%rsi), %rdx
|
; asm: movslq -50(%rsi), %rdx
|
||||||
[-,%rdx] v145 = sload32.i64 v2-50 ; bin: 48 63 56 ce
|
[-,%rdx] v145 = sload32.i64 v2-50 ; bin: heap_oob 48 63 56 ce
|
||||||
; asm: movzwq 50(%rcx), %rdi
|
; asm: movzwq 50(%rcx), %rdi
|
||||||
[-,%rdi] v146 = uload16.i64 v1+50 ; bin: 48 0f b7 79 32
|
[-,%rdi] v146 = uload16.i64 v1+50 ; bin: heap_oob 48 0f b7 79 32
|
||||||
; asm: movzwq -50(%rsi), %rdx
|
; asm: movzwq -50(%rsi), %rdx
|
||||||
[-,%rdx] v147 = uload16.i64 v2-50 ; bin: 48 0f b7 56 ce
|
[-,%rdx] v147 = uload16.i64 v2-50 ; bin: heap_oob 48 0f b7 56 ce
|
||||||
; asm: movswq 50(%rcx), %rdi
|
; asm: movswq 50(%rcx), %rdi
|
||||||
[-,%rdi] v148 = sload16.i64 v1+50 ; bin: 48 0f bf 79 32
|
[-,%rdi] v148 = sload16.i64 v1+50 ; bin: heap_oob 48 0f bf 79 32
|
||||||
; asm: movswq -50(%rsi), %rdx
|
; asm: movswq -50(%rsi), %rdx
|
||||||
[-,%rdx] v149 = sload16.i64 v2-50 ; bin: 48 0f bf 56 ce
|
[-,%rdx] v149 = sload16.i64 v2-50 ; bin: heap_oob 48 0f bf 56 ce
|
||||||
; asm: movzbq 50(%rcx), %rdi
|
; asm: movzbq 50(%rcx), %rdi
|
||||||
[-,%rdi] v150 = uload8.i64 v1+50 ; bin: 48 0f b6 79 32
|
[-,%rdi] v150 = uload8.i64 v1+50 ; bin: heap_oob 48 0f b6 79 32
|
||||||
; asm: movzbq -50(%rsi), %rdx
|
; asm: movzbq -50(%rsi), %rdx
|
||||||
[-,%rdx] v151 = uload8.i64 v2-50 ; bin: 48 0f b6 56 ce
|
[-,%rdx] v151 = uload8.i64 v2-50 ; bin: heap_oob 48 0f b6 56 ce
|
||||||
; asm: movsbq 50(%rcx), %rdi
|
; asm: movsbq 50(%rcx), %rdi
|
||||||
[-,%rdi] v152 = sload8.i64 v1+50 ; bin: 48 0f be 79 32
|
[-,%rdi] v152 = sload8.i64 v1+50 ; bin: heap_oob 48 0f be 79 32
|
||||||
; asm: movsbq -50(%rsi), %rdx
|
; asm: movsbq -50(%rsi), %rdx
|
||||||
[-,%rdx] v153 = sload8.i64 v2-50 ; bin: 48 0f be 56 ce
|
[-,%rdx] v153 = sload8.i64 v2-50 ; bin: heap_oob 48 0f be 56 ce
|
||||||
|
|
||||||
; Register-indirect with 32-bit signed displacement.
|
; Register-indirect with 32-bit signed displacement.
|
||||||
|
|
||||||
; asm: movq %rcx, 10000(%r10)
|
; asm: movq %rcx, 10000(%r10)
|
||||||
store v1, v3+10000 ; bin: 49 89 8a 00002710
|
store v1, v3+10000 ; bin: heap_oob 49 89 8a 00002710
|
||||||
; asm: movq %r10, -10000(%rcx)
|
; asm: movq %r10, -10000(%rcx)
|
||||||
store v3, v1-10000 ; bin: 4c 89 91 ffffd8f0
|
store v3, v1-10000 ; bin: heap_oob 4c 89 91 ffffd8f0
|
||||||
; asm: movl %ecx, 10000(%rsi)
|
; asm: movl %ecx, 10000(%rsi)
|
||||||
istore32 v1, v2+10000 ; bin: 89 8e 00002710
|
istore32 v1, v2+10000 ; bin: heap_oob 89 8e 00002710
|
||||||
; asm: movl %esi, -10000(%rcx)
|
; asm: movl %esi, -10000(%rcx)
|
||||||
istore32 v2, v1-10000 ; bin: 89 b1 ffffd8f0
|
istore32 v2, v1-10000 ; bin: heap_oob 89 b1 ffffd8f0
|
||||||
; asm: movw %cx, 10000(%rsi)
|
; asm: movw %cx, 10000(%rsi)
|
||||||
istore16 v1, v2+10000 ; bin: 66 89 8e 00002710
|
istore16 v1, v2+10000 ; bin: heap_oob 66 89 8e 00002710
|
||||||
; asm: movw %si, -10000(%rcx)
|
; asm: movw %si, -10000(%rcx)
|
||||||
istore16 v2, v1-10000 ; bin: 66 89 b1 ffffd8f0
|
istore16 v2, v1-10000 ; bin: heap_oob 66 89 b1 ffffd8f0
|
||||||
; asm: movb %cl, 10000(%rsi)
|
; asm: movb %cl, 10000(%rsi)
|
||||||
istore8 v1, v2+10000 ; bin: 88 8e 00002710
|
istore8 v1, v2+10000 ; bin: heap_oob 88 8e 00002710
|
||||||
; asm: movb %sil, 10000(%rcx)
|
; asm: movb %sil, 10000(%rcx)
|
||||||
istore8 v2, v1+10000 ; bin: 40 88 b1 00002710
|
istore8 v2, v1+10000 ; bin: heap_oob 40 88 b1 00002710
|
||||||
|
|
||||||
; asm: movq 50000(%rcx), %r10
|
; asm: movq 50000(%rcx), %r10
|
||||||
[-,%r10] v160 = load.i64 v1+50000 ; bin: 4c 8b 91 0000c350
|
[-,%r10] v160 = load.i64 v1+50000 ; bin: heap_oob 4c 8b 91 0000c350
|
||||||
; asm: movq -50000(%r10), %rdx
|
; asm: movq -50000(%r10), %rdx
|
||||||
[-,%rdx] v161 = load.i64 v3-50000 ; bin: 49 8b 92 ffff3cb0
|
[-,%rdx] v161 = load.i64 v3-50000 ; bin: heap_oob 49 8b 92 ffff3cb0
|
||||||
; asm: movl 50000(%rcx), %edi
|
; asm: movl 50000(%rcx), %edi
|
||||||
[-,%rdi] v162 = uload32.i64 v1+50000 ; bin: 8b b9 0000c350
|
[-,%rdi] v162 = uload32.i64 v1+50000 ; bin: heap_oob 8b b9 0000c350
|
||||||
; asm: movl -50000(%rsi), %edx
|
; asm: movl -50000(%rsi), %edx
|
||||||
[-,%rdx] v163 = uload32.i64 v2-50000 ; bin: 8b 96 ffff3cb0
|
[-,%rdx] v163 = uload32.i64 v2-50000 ; bin: heap_oob 8b 96 ffff3cb0
|
||||||
; asm: movslq 50000(%rcx), %rdi
|
; asm: movslq 50000(%rcx), %rdi
|
||||||
[-,%rdi] v164 = sload32.i64 v1+50000 ; bin: 48 63 b9 0000c350
|
[-,%rdi] v164 = sload32.i64 v1+50000 ; bin: heap_oob 48 63 b9 0000c350
|
||||||
; asm: movslq -50000(%rsi), %rdx
|
; asm: movslq -50000(%rsi), %rdx
|
||||||
[-,%rdx] v165 = sload32.i64 v2-50000 ; bin: 48 63 96 ffff3cb0
|
[-,%rdx] v165 = sload32.i64 v2-50000 ; bin: heap_oob 48 63 96 ffff3cb0
|
||||||
; asm: movzwq 50000(%rcx), %rdi
|
; asm: movzwq 50000(%rcx), %rdi
|
||||||
[-,%rdi] v166 = uload16.i64 v1+50000 ; bin: 48 0f b7 b9 0000c350
|
[-,%rdi] v166 = uload16.i64 v1+50000 ; bin: heap_oob 48 0f b7 b9 0000c350
|
||||||
; asm: movzwq -50000(%rsi), %rdx
|
; asm: movzwq -50000(%rsi), %rdx
|
||||||
[-,%rdx] v167 = uload16.i64 v2-50000 ; bin: 48 0f b7 96 ffff3cb0
|
[-,%rdx] v167 = uload16.i64 v2-50000 ; bin: heap_oob 48 0f b7 96 ffff3cb0
|
||||||
; asm: movswq 50000(%rcx), %rdi
|
; asm: movswq 50000(%rcx), %rdi
|
||||||
[-,%rdi] v168 = sload16.i64 v1+50000 ; bin: 48 0f bf b9 0000c350
|
[-,%rdi] v168 = sload16.i64 v1+50000 ; bin: heap_oob 48 0f bf b9 0000c350
|
||||||
; asm: movswq -50000(%rsi), %rdx
|
; asm: movswq -50000(%rsi), %rdx
|
||||||
[-,%rdx] v169 = sload16.i64 v2-50000 ; bin: 48 0f bf 96 ffff3cb0
|
[-,%rdx] v169 = sload16.i64 v2-50000 ; bin: heap_oob 48 0f bf 96 ffff3cb0
|
||||||
; asm: movzbq 50000(%rcx), %rdi
|
; asm: movzbq 50000(%rcx), %rdi
|
||||||
[-,%rdi] v170 = uload8.i64 v1+50000 ; bin: 48 0f b6 b9 0000c350
|
[-,%rdi] v170 = uload8.i64 v1+50000 ; bin: heap_oob 48 0f b6 b9 0000c350
|
||||||
; asm: movzbq -50000(%rsi), %rdx
|
; asm: movzbq -50000(%rsi), %rdx
|
||||||
[-,%rdx] v171 = uload8.i64 v2-50000 ; bin: 48 0f b6 96 ffff3cb0
|
[-,%rdx] v171 = uload8.i64 v2-50000 ; bin: heap_oob 48 0f b6 96 ffff3cb0
|
||||||
; asm: movsbq 50000(%rcx), %rdi
|
; asm: movsbq 50000(%rcx), %rdi
|
||||||
[-,%rdi] v172 = sload8.i64 v1+50000 ; bin: 48 0f be b9 0000c350
|
[-,%rdi] v172 = sload8.i64 v1+50000 ; bin: heap_oob 48 0f be b9 0000c350
|
||||||
; asm: movsbq -50000(%rsi), %rdx
|
; asm: movsbq -50000(%rsi), %rdx
|
||||||
[-,%rdx] v173 = sload8.i64 v2-50000 ; bin: 48 0f be 96 ffff3cb0
|
[-,%rdx] v173 = sload8.i64 v2-50000 ; bin: heap_oob 48 0f be 96 ffff3cb0
|
||||||
|
|
||||||
|
|
||||||
; More arithmetic.
|
; More arithmetic.
|
||||||
@@ -324,17 +329,17 @@ ebb0:
|
|||||||
[-,%rax] v190 = iconst.i64 1
|
[-,%rax] v190 = iconst.i64 1
|
||||||
[-,%rdx] v191 = iconst.i64 2
|
[-,%rdx] v191 = iconst.i64 2
|
||||||
; asm: idivq %rcx
|
; asm: idivq %rcx
|
||||||
[-,%rax,%rdx] v192, v193 = x86_sdivmodx v190, v191, v1 ; bin: 48 f7 f9
|
[-,%rax,%rdx] v192, v193 = x86_sdivmodx v190, v191, v1 ; bin: int_divz 48 f7 f9
|
||||||
; asm: idivq %rsi
|
; asm: idivq %rsi
|
||||||
[-,%rax,%rdx] v194, v195 = x86_sdivmodx v190, v191, v2 ; bin: 48 f7 fe
|
[-,%rax,%rdx] v194, v195 = x86_sdivmodx v190, v191, v2 ; bin: int_divz 48 f7 fe
|
||||||
; asm: idivq %r10
|
; asm: idivq %r10
|
||||||
[-,%rax,%rdx] v196, v197 = x86_sdivmodx v190, v191, v3 ; bin: 49 f7 fa
|
[-,%rax,%rdx] v196, v197 = x86_sdivmodx v190, v191, v3 ; bin: int_divz 49 f7 fa
|
||||||
; asm: divq %rcx
|
; asm: divq %rcx
|
||||||
[-,%rax,%rdx] v198, v199 = x86_udivmodx v190, v191, v1 ; bin: 48 f7 f1
|
[-,%rax,%rdx] v198, v199 = x86_udivmodx v190, v191, v1 ; bin: int_divz 48 f7 f1
|
||||||
; asm: divq %rsi
|
; asm: divq %rsi
|
||||||
[-,%rax,%rdx] v200, v201 = x86_udivmodx v190, v191, v2 ; bin: 48 f7 f6
|
[-,%rax,%rdx] v200, v201 = x86_udivmodx v190, v191, v2 ; bin: int_divz 48 f7 f6
|
||||||
; asm: divq %r10
|
; asm: divq %r10
|
||||||
[-,%rax,%rdx] v202, v203 = x86_udivmodx v190, v191, v3 ; bin: 49 f7 f2
|
[-,%rax,%rdx] v202, v203 = x86_udivmodx v190, v191, v3 ; bin: int_divz 49 f7 f2
|
||||||
|
|
||||||
; double-length multiply instructions, 64 bit
|
; double-length multiply instructions, 64 bit
|
||||||
[-,%rax] v1001 = iconst.i64 1
|
[-,%rax] v1001 = iconst.i64 1
|
||||||
@@ -453,6 +458,14 @@ ebb0:
|
|||||||
; asm: setbe %dl
|
; asm: setbe %dl
|
||||||
[-,%rdx] v319 = icmp ule v2, v3 ; bin: 4c 39 d6 0f 96 c2
|
[-,%rdx] v319 = icmp ule v2, v3 ; bin: 4c 39 d6 0f 96 c2
|
||||||
|
|
||||||
|
; asm: cmpq $37, %rcx
|
||||||
|
; asm: setl %bl
|
||||||
|
[-,%rbx] v320 = icmp_imm slt v1, 37 ; bin: 48 83 f9 25 0f 9c c3
|
||||||
|
|
||||||
|
; asm: cmpq $100000, %rcx
|
||||||
|
; asm: setl %bl
|
||||||
|
[-,%rbx] v321 = icmp_imm slt v1, 100000 ; bin: 48 81 f9 000186a0 0f 9c c3
|
||||||
|
|
||||||
; Bool-to-int conversions.
|
; Bool-to-int conversions.
|
||||||
|
|
||||||
; asm: movzbq %bl, %rcx
|
; asm: movzbq %bl, %rcx
|
||||||
@@ -529,6 +542,21 @@ ebb0:
|
|||||||
; asm: addq $-2147483648, %rsp
|
; asm: addq $-2147483648, %rsp
|
||||||
adjust_sp_imm -2147483648 ; bin: 48 81 c4 80000000
|
adjust_sp_imm -2147483648 ; bin: 48 81 c4 80000000
|
||||||
|
|
||||||
|
; Shift immediates
|
||||||
|
; asm: shlq $12, %rsi
|
||||||
|
[-,%rsi] v515 = ishl_imm v2, 12 ; bin: 48 c1 e6 0c
|
||||||
|
; asm: shlq $13, %r8
|
||||||
|
[-,%r8] v516 = ishl_imm v4, 13 ; bin: 49 c1 e0 0d
|
||||||
|
; asm: sarq $32, %rsi
|
||||||
|
[-,%rsi] v517 = sshr_imm v2, 32 ; bin: 48 c1 fe 20
|
||||||
|
; asm: sarq $33, %r8
|
||||||
|
[-,%r8] v518 = sshr_imm v4, 33 ; bin: 49 c1 f8 21
|
||||||
|
; asm: shrl $62, %rsi
|
||||||
|
[-,%rsi] v519 = ushr_imm v2, 62 ; bin: 48 c1 ee 3e
|
||||||
|
; asm: shrl $63, %r8
|
||||||
|
[-,%r8] v520 = ushr_imm v4, 63 ; bin: 49 c1 e8 3f
|
||||||
|
|
||||||
|
|
||||||
; asm: testq %rcx, %rcx
|
; asm: testq %rcx, %rcx
|
||||||
; asm: je ebb1
|
; asm: je ebb1
|
||||||
brz v1, ebb1 ; bin: 48 85 c9 74 1b
|
brz v1, ebb1 ; bin: 48 85 c9 74 1b
|
||||||
@@ -569,9 +597,9 @@ ebb0:
|
|||||||
|
|
||||||
ebb1:
|
ebb1:
|
||||||
; asm: cmpq %r10, %rcx
|
; asm: cmpq %r10, %rcx
|
||||||
[-,%eflags] v10 = ifcmp v1, v2 ; bin: 4c 39 d1
|
[-,%rflags] v10 = ifcmp v1, v2 ; bin: 4c 39 d1
|
||||||
; asm: cmpq %rcx, %r10
|
; asm: cmpq %rcx, %r10
|
||||||
[-,%eflags] v11 = ifcmp v2, v1 ; bin: 49 39 ca
|
[-,%rflags] v11 = ifcmp v2, v1 ; bin: 49 39 ca
|
||||||
|
|
||||||
; asm: je ebb1
|
; asm: je ebb1
|
||||||
brif eq v11, ebb1 ; bin: 74 f8
|
brif eq v11, ebb1 ; bin: 74 f8
|
||||||
@@ -617,41 +645,42 @@ ebb1:
|
|||||||
|
|
||||||
; The trapif instructions are encoded as macros: a conditional jump over a ud2.
|
; The trapif instructions are encoded as macros: a conditional jump over a ud2.
|
||||||
; asm: jne .+4; ud2
|
; asm: jne .+4; ud2
|
||||||
trapif eq v11, user0 ; bin: 75 02 0f 0b
|
trapif eq v11, user0 ; bin: 75 02 user0 0f 0b
|
||||||
; asm: je .+4; ud2
|
; asm: je .+4; ud2
|
||||||
trapif ne v11, user0 ; bin: 74 02 0f 0b
|
trapif ne v11, user0 ; bin: 74 02 user0 0f 0b
|
||||||
; asm: jnl .+4; ud2
|
; asm: jnl .+4; ud2
|
||||||
trapif slt v11, user0 ; bin: 7d 02 0f 0b
|
trapif slt v11, user0 ; bin: 7d 02 user0 0f 0b
|
||||||
; asm: jnge .+4; ud2
|
; asm: jnge .+4; ud2
|
||||||
trapif sge v11, user0 ; bin: 7c 02 0f 0b
|
trapif sge v11, user0 ; bin: 7c 02 user0 0f 0b
|
||||||
; asm: jng .+4; ud2
|
; asm: jng .+4; ud2
|
||||||
trapif sgt v11, user0 ; bin: 7e 02 0f 0b
|
trapif sgt v11, user0 ; bin: 7e 02 user0 0f 0b
|
||||||
; asm: jnle .+4; ud2
|
; asm: jnle .+4; ud2
|
||||||
trapif sle v11, user0 ; bin: 7f 02 0f 0b
|
trapif sle v11, user0 ; bin: 7f 02 user0 0f 0b
|
||||||
; asm: jnb .+4; ud2
|
; asm: jnb .+4; ud2
|
||||||
trapif ult v11, user0 ; bin: 73 02 0f 0b
|
trapif ult v11, user0 ; bin: 73 02 user0 0f 0b
|
||||||
; asm: jnae .+4; ud2
|
; asm: jnae .+4; ud2
|
||||||
trapif uge v11, user0 ; bin: 72 02 0f 0b
|
trapif uge v11, user0 ; bin: 72 02 user0 0f 0b
|
||||||
; asm: jna .+4; ud2
|
; asm: jna .+4; ud2
|
||||||
trapif ugt v11, user0 ; bin: 76 02 0f 0b
|
trapif ugt v11, user0 ; bin: 76 02 user0 0f 0b
|
||||||
; asm: jnbe .+4; ud2
|
; asm: jnbe .+4; ud2
|
||||||
trapif ule v11, user0 ; bin: 77 02 0f 0b
|
trapif ule v11, user0 ; bin: 77 02 user0 0f 0b
|
||||||
|
|
||||||
; Stack check.
|
; Stack check.
|
||||||
; asm: cmpq %rsp, %rcx
|
; asm: cmpq %rsp, %rcx
|
||||||
[-,%eflags] v40 = ifcmp_sp v1 ; bin: 48 39 e1
|
[-,%rflags] v40 = ifcmp_sp v1 ; bin: 48 39 e1
|
||||||
; asm: cmpq %rsp, %r10
|
; asm: cmpq %rsp, %r10
|
||||||
[-,%eflags] v41 = ifcmp_sp v2 ; bin: 49 39 e2
|
[-,%rflags] v41 = ifcmp_sp v2 ; bin: 49 39 e2
|
||||||
|
|
||||||
; asm: cmpq $-100, %rcx
|
; asm: cmpq $-100, %rcx
|
||||||
[-,%eflags] v522 = ifcmp_imm v1, -100 ; bin: 48 83 f9 9c
|
[-,%rflags] v522 = ifcmp_imm v1, -100 ; bin: 48 83 f9 9c
|
||||||
; asm: cmpq $100, %r10
|
; asm: cmpq $100, %r10
|
||||||
[-,%eflags] v523 = ifcmp_imm v2, 100 ; bin: 49 83 fa 64
|
[-,%rflags] v523 = ifcmp_imm v2, 100 ; bin: 49 83 fa 64
|
||||||
|
|
||||||
; asm: cmpq $-10000, %rcx
|
; asm: cmpq $-10000, %rcx
|
||||||
[-,%eflags] v524 = ifcmp_imm v1, -10000 ; bin: 48 81 f9 ffffd8f0
|
[-,%rflags] v524 = ifcmp_imm v1, -10000 ; bin: 48 81 f9 ffffd8f0
|
||||||
; asm: cmpq $10000, %r10
|
; asm: cmpq $10000, %r10
|
||||||
[-,%eflags] v525 = ifcmp_imm v2, 10000 ; bin: 49 81 fa 00002710
|
[-,%rflags] v525 = ifcmp_imm v2, 10000 ; bin: 49 81 fa 00002710
|
||||||
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -708,71 +737,71 @@ ebb0:
|
|||||||
; Register indirect addressing with no displacement.
|
; Register indirect addressing with no displacement.
|
||||||
|
|
||||||
; asm: movl (%rcx), %edi
|
; asm: movl (%rcx), %edi
|
||||||
[-,%rdi] v10 = load.i32 v1 ; bin: 8b 39
|
[-,%rdi] v10 = load.i32 v1 ; bin: heap_oob 8b 39
|
||||||
; asm: movl (%rsi), %edx
|
; asm: movl (%rsi), %edx
|
||||||
[-,%rdx] v11 = load.i32 v2 ; bin: 8b 16
|
[-,%rdx] v11 = load.i32 v2 ; bin: heap_oob 8b 16
|
||||||
; asm: movzwl (%rcx), %edi
|
; asm: movzwl (%rcx), %edi
|
||||||
[-,%rdi] v12 = uload16.i32 v1 ; bin: 0f b7 39
|
[-,%rdi] v12 = uload16.i32 v1 ; bin: heap_oob 0f b7 39
|
||||||
; asm: movzwl (%rsi), %edx
|
; asm: movzwl (%rsi), %edx
|
||||||
[-,%rdx] v13 = uload16.i32 v2 ; bin: 0f b7 16
|
[-,%rdx] v13 = uload16.i32 v2 ; bin: heap_oob 0f b7 16
|
||||||
; asm: movswl (%rcx), %edi
|
; asm: movswl (%rcx), %edi
|
||||||
[-,%rdi] v14 = sload16.i32 v1 ; bin: 0f bf 39
|
[-,%rdi] v14 = sload16.i32 v1 ; bin: heap_oob 0f bf 39
|
||||||
; asm: movswl (%rsi), %edx
|
; asm: movswl (%rsi), %edx
|
||||||
[-,%rdx] v15 = sload16.i32 v2 ; bin: 0f bf 16
|
[-,%rdx] v15 = sload16.i32 v2 ; bin: heap_oob 0f bf 16
|
||||||
; asm: movzbl (%rcx), %edi
|
; asm: movzbl (%rcx), %edi
|
||||||
[-,%rdi] v16 = uload8.i32 v1 ; bin: 0f b6 39
|
[-,%rdi] v16 = uload8.i32 v1 ; bin: heap_oob 0f b6 39
|
||||||
; asm: movzbl (%rsi), %edx
|
; asm: movzbl (%rsi), %edx
|
||||||
[-,%rdx] v17 = uload8.i32 v2 ; bin: 0f b6 16
|
[-,%rdx] v17 = uload8.i32 v2 ; bin: heap_oob 0f b6 16
|
||||||
; asm: movsbl (%rcx), %edi
|
; asm: movsbl (%rcx), %edi
|
||||||
[-,%rdi] v18 = sload8.i32 v1 ; bin: 0f be 39
|
[-,%rdi] v18 = sload8.i32 v1 ; bin: heap_oob 0f be 39
|
||||||
; asm: movsbl (%rsi), %edx
|
; asm: movsbl (%rsi), %edx
|
||||||
[-,%rdx] v19 = sload8.i32 v2 ; bin: 0f be 16
|
[-,%rdx] v19 = sload8.i32 v2 ; bin: heap_oob 0f be 16
|
||||||
|
|
||||||
; Register-indirect with 8-bit signed displacement.
|
; Register-indirect with 8-bit signed displacement.
|
||||||
|
|
||||||
; asm: movl 50(%rcx), %edi
|
; asm: movl 50(%rcx), %edi
|
||||||
[-,%rdi] v20 = load.i32 v1+50 ; bin: 8b 79 32
|
[-,%rdi] v20 = load.i32 v1+50 ; bin: heap_oob 8b 79 32
|
||||||
; asm: movl -50(%rsi), %edx
|
; asm: movl -50(%rsi), %edx
|
||||||
[-,%rdx] v21 = load.i32 v2-50 ; bin: 8b 56 ce
|
[-,%rdx] v21 = load.i32 v2-50 ; bin: heap_oob 8b 56 ce
|
||||||
; asm: movzwl 50(%rcx), %edi
|
; asm: movzwl 50(%rcx), %edi
|
||||||
[-,%rdi] v22 = uload16.i32 v1+50 ; bin: 0f b7 79 32
|
[-,%rdi] v22 = uload16.i32 v1+50 ; bin: heap_oob 0f b7 79 32
|
||||||
; asm: movzwl -50(%rsi), %edx
|
; asm: movzwl -50(%rsi), %edx
|
||||||
[-,%rdx] v23 = uload16.i32 v2-50 ; bin: 0f b7 56 ce
|
[-,%rdx] v23 = uload16.i32 v2-50 ; bin: heap_oob 0f b7 56 ce
|
||||||
; asm: movswl 50(%rcx), %edi
|
; asm: movswl 50(%rcx), %edi
|
||||||
[-,%rdi] v24 = sload16.i32 v1+50 ; bin: 0f bf 79 32
|
[-,%rdi] v24 = sload16.i32 v1+50 ; bin: heap_oob 0f bf 79 32
|
||||||
; asm: movswl -50(%rsi), %edx
|
; asm: movswl -50(%rsi), %edx
|
||||||
[-,%rdx] v25 = sload16.i32 v2-50 ; bin: 0f bf 56 ce
|
[-,%rdx] v25 = sload16.i32 v2-50 ; bin: heap_oob 0f bf 56 ce
|
||||||
; asm: movzbl 50(%rcx), %edi
|
; asm: movzbl 50(%rcx), %edi
|
||||||
[-,%rdi] v26 = uload8.i32 v1+50 ; bin: 0f b6 79 32
|
[-,%rdi] v26 = uload8.i32 v1+50 ; bin: heap_oob 0f b6 79 32
|
||||||
; asm: movzbl -50(%rsi), %edx
|
; asm: movzbl -50(%rsi), %edx
|
||||||
[-,%rdx] v27 = uload8.i32 v2-50 ; bin: 0f b6 56 ce
|
[-,%rdx] v27 = uload8.i32 v2-50 ; bin: heap_oob 0f b6 56 ce
|
||||||
; asm: movsbl 50(%rcx), %edi
|
; asm: movsbl 50(%rcx), %edi
|
||||||
[-,%rdi] v28 = sload8.i32 v1+50 ; bin: 0f be 79 32
|
[-,%rdi] v28 = sload8.i32 v1+50 ; bin: heap_oob 0f be 79 32
|
||||||
; asm: movsbl -50(%rsi), %edx
|
; asm: movsbl -50(%rsi), %edx
|
||||||
[-,%rdx] v29 = sload8.i32 v2-50 ; bin: 0f be 56 ce
|
[-,%rdx] v29 = sload8.i32 v2-50 ; bin: heap_oob 0f be 56 ce
|
||||||
|
|
||||||
; Register-indirect with 32-bit signed displacement.
|
; Register-indirect with 32-bit signed displacement.
|
||||||
|
|
||||||
; asm: movl 50000(%rcx), %edi
|
; asm: movl 50000(%rcx), %edi
|
||||||
[-,%rdi] v30 = load.i32 v1+50000 ; bin: 8b b9 0000c350
|
[-,%rdi] v30 = load.i32 v1+50000 ; bin: heap_oob 8b b9 0000c350
|
||||||
; asm: movl -50000(%rsi), %edx
|
; asm: movl -50000(%rsi), %edx
|
||||||
[-,%rdx] v31 = load.i32 v2-50000 ; bin: 8b 96 ffff3cb0
|
[-,%rdx] v31 = load.i32 v2-50000 ; bin: heap_oob 8b 96 ffff3cb0
|
||||||
; asm: movzwl 50000(%rcx), %edi
|
; asm: movzwl 50000(%rcx), %edi
|
||||||
[-,%rdi] v32 = uload16.i32 v1+50000 ; bin: 0f b7 b9 0000c350
|
[-,%rdi] v32 = uload16.i32 v1+50000 ; bin: heap_oob 0f b7 b9 0000c350
|
||||||
; asm: movzwl -50000(%rsi), %edx
|
; asm: movzwl -50000(%rsi), %edx
|
||||||
[-,%rdx] v33 = uload16.i32 v2-50000 ; bin: 0f b7 96 ffff3cb0
|
[-,%rdx] v33 = uload16.i32 v2-50000 ; bin: heap_oob 0f b7 96 ffff3cb0
|
||||||
; asm: movswl 50000(%rcx), %edi
|
; asm: movswl 50000(%rcx), %edi
|
||||||
[-,%rdi] v34 = sload16.i32 v1+50000 ; bin: 0f bf b9 0000c350
|
[-,%rdi] v34 = sload16.i32 v1+50000 ; bin: heap_oob 0f bf b9 0000c350
|
||||||
; asm: movswl -50000(%rsi), %edx
|
; asm: movswl -50000(%rsi), %edx
|
||||||
[-,%rdx] v35 = sload16.i32 v2-50000 ; bin: 0f bf 96 ffff3cb0
|
[-,%rdx] v35 = sload16.i32 v2-50000 ; bin: heap_oob 0f bf 96 ffff3cb0
|
||||||
; asm: movzbl 50000(%rcx), %edi
|
; asm: movzbl 50000(%rcx), %edi
|
||||||
[-,%rdi] v36 = uload8.i32 v1+50000 ; bin: 0f b6 b9 0000c350
|
[-,%rdi] v36 = uload8.i32 v1+50000 ; bin: heap_oob 0f b6 b9 0000c350
|
||||||
; asm: movzbl -50000(%rsi), %edx
|
; asm: movzbl -50000(%rsi), %edx
|
||||||
[-,%rdx] v37 = uload8.i32 v2-50000 ; bin: 0f b6 96 ffff3cb0
|
[-,%rdx] v37 = uload8.i32 v2-50000 ; bin: heap_oob 0f b6 96 ffff3cb0
|
||||||
; asm: movsbl 50000(%rcx), %edi
|
; asm: movsbl 50000(%rcx), %edi
|
||||||
[-,%rdi] v38 = sload8.i32 v1+50000 ; bin: 0f be b9 0000c350
|
[-,%rdi] v38 = sload8.i32 v1+50000 ; bin: heap_oob 0f be b9 0000c350
|
||||||
; asm: movsbl -50000(%rsi), %edx
|
; asm: movsbl -50000(%rsi), %edx
|
||||||
[-,%rdx] v39 = sload8.i32 v2-50000 ; bin: 0f be 96 ffff3cb0
|
[-,%rdx] v39 = sload8.i32 v2-50000 ; bin: heap_oob 0f be 96 ffff3cb0
|
||||||
|
|
||||||
; Integer Register-Register Operations.
|
; Integer Register-Register Operations.
|
||||||
|
|
||||||
@@ -903,17 +932,17 @@ ebb0:
|
|||||||
[-,%rax] v160 = iconst.i32 1
|
[-,%rax] v160 = iconst.i32 1
|
||||||
[-,%rdx] v161 = iconst.i32 2
|
[-,%rdx] v161 = iconst.i32 2
|
||||||
; asm: idivl %ecx
|
; asm: idivl %ecx
|
||||||
[-,%rax,%rdx] v162, v163 = x86_sdivmodx v160, v161, v1 ; bin: f7 f9
|
[-,%rax,%rdx] v162, v163 = x86_sdivmodx v160, v161, v1 ; bin: int_divz f7 f9
|
||||||
; asm: idivl %esi
|
; asm: idivl %esi
|
||||||
[-,%rax,%rdx] v164, v165 = x86_sdivmodx v160, v161, v2 ; bin: f7 fe
|
[-,%rax,%rdx] v164, v165 = x86_sdivmodx v160, v161, v2 ; bin: int_divz f7 fe
|
||||||
; asm: idivl %r10d
|
; asm: idivl %r10d
|
||||||
[-,%rax,%rdx] v166, v167 = x86_sdivmodx v160, v161, v3 ; bin: 41 f7 fa
|
[-,%rax,%rdx] v166, v167 = x86_sdivmodx v160, v161, v3 ; bin: int_divz 41 f7 fa
|
||||||
; asm: divl %ecx
|
; asm: divl %ecx
|
||||||
[-,%rax,%rdx] v168, v169 = x86_udivmodx v160, v161, v1 ; bin: f7 f1
|
[-,%rax,%rdx] v168, v169 = x86_udivmodx v160, v161, v1 ; bin: int_divz f7 f1
|
||||||
; asm: divl %esi
|
; asm: divl %esi
|
||||||
[-,%rax,%rdx] v170, v171 = x86_udivmodx v160, v161, v2 ; bin: f7 f6
|
[-,%rax,%rdx] v170, v171 = x86_udivmodx v160, v161, v2 ; bin: int_divz f7 f6
|
||||||
; asm: divl %r10d
|
; asm: divl %r10d
|
||||||
[-,%rax,%rdx] v172, v173 = x86_udivmodx v160, v161, v3 ; bin: 41 f7 f2
|
[-,%rax,%rdx] v172, v173 = x86_udivmodx v160, v161, v3 ; bin: int_divz 41 f7 f2
|
||||||
|
|
||||||
; Bit-counting instructions.
|
; Bit-counting instructions.
|
||||||
|
|
||||||
@@ -1010,6 +1039,14 @@ ebb0:
|
|||||||
; asm: setbe %dl
|
; asm: setbe %dl
|
||||||
[-,%rdx] v319 = icmp ule v2, v3 ; bin: 44 39 d6 0f 96 c2
|
[-,%rdx] v319 = icmp ule v2, v3 ; bin: 44 39 d6 0f 96 c2
|
||||||
|
|
||||||
|
; asm: cmpl $37, %ecx
|
||||||
|
; asm: setl %bl
|
||||||
|
[-,%rbx] v320 = icmp_imm slt v1, 37 ; bin: 83 f9 25 0f 9c c3
|
||||||
|
|
||||||
|
; asm: cmpq $100000, %ecx
|
||||||
|
; asm: setl %bl
|
||||||
|
[-,%rbx] v321 = icmp_imm slt v1, 100000 ; bin: 81 f9 000186a0 0f 9c c3
|
||||||
|
|
||||||
; Bool-to-int conversions.
|
; Bool-to-int conversions.
|
||||||
|
|
||||||
; asm: movzbl %bl, %ecx
|
; asm: movzbl %bl, %ecx
|
||||||
@@ -1039,19 +1076,32 @@ ebb0:
|
|||||||
regfill v1, ss1 -> %rcx ; bin: 8b 8c 24 00000408
|
regfill v1, ss1 -> %rcx ; bin: 8b 8c 24 00000408
|
||||||
|
|
||||||
; asm: cmpl %esi, %ecx
|
; asm: cmpl %esi, %ecx
|
||||||
[-,%eflags] v520 = ifcmp v1, v2 ; bin: 39 f1
|
[-,%rflags] v520 = ifcmp v1, v2 ; bin: 39 f1
|
||||||
; asm: cmpl %r10d, %esi
|
; asm: cmpl %r10d, %esi
|
||||||
[-,%eflags] v521 = ifcmp v2, v3 ; bin: 44 39 d6
|
[-,%rflags] v521 = ifcmp v2, v3 ; bin: 44 39 d6
|
||||||
|
|
||||||
; asm: cmpl $-100, %ecx
|
; asm: cmpl $-100, %ecx
|
||||||
[-,%eflags] v522 = ifcmp_imm v1, -100 ; bin: 83 f9 9c
|
[-,%rflags] v522 = ifcmp_imm v1, -100 ; bin: 83 f9 9c
|
||||||
; asm: cmpl $100, %r10d
|
; asm: cmpl $100, %r10d
|
||||||
[-,%eflags] v523 = ifcmp_imm v3, 100 ; bin: 41 83 fa 64
|
[-,%rflags] v523 = ifcmp_imm v3, 100 ; bin: 41 83 fa 64
|
||||||
|
|
||||||
; asm: cmpl $-10000, %ecx
|
; asm: cmpl $-10000, %ecx
|
||||||
[-,%eflags] v524 = ifcmp_imm v1, -10000 ; bin: 81 f9 ffffd8f0
|
[-,%rflags] v524 = ifcmp_imm v1, -10000 ; bin: 81 f9 ffffd8f0
|
||||||
; asm: cmpl $10000, %r10d
|
; asm: cmpl $10000, %r10d
|
||||||
[-,%eflags] v525 = ifcmp_imm v3, 10000 ; bin: 41 81 fa 00002710
|
[-,%rflags] v525 = ifcmp_imm v3, 10000 ; bin: 41 81 fa 00002710
|
||||||
|
|
||||||
|
; asm: shll $2, %esi
|
||||||
|
[-,%rsi] v526 = ishl_imm v2, 2 ; bin: c1 e6 02
|
||||||
|
; asm: shll $12, %r10d
|
||||||
|
[-,%r10] v527 = ishl_imm v3, 12 ; bin: 41 c1 e2 0c
|
||||||
|
; asm: sarl $5, %esi
|
||||||
|
[-,%rsi] v529 = sshr_imm v2, 5 ; bin: c1 fe 05
|
||||||
|
; asm: sarl $32, %r10d
|
||||||
|
[-,%r10] v530 = sshr_imm v3, 32 ; bin: 41 c1 fa 20
|
||||||
|
; asm: shrl $8, %esi
|
||||||
|
[-,%rsi] v532 = ushr_imm v2, 8 ; bin: c1 ee 08
|
||||||
|
; asm: shrl $31, %r10d
|
||||||
|
[-,%r10] v533 = ushr_imm v3, 31 ; bin: 41 c1 ea 1f
|
||||||
|
|
||||||
; asm: testl %ecx, %ecx
|
; asm: testl %ecx, %ecx
|
||||||
; asm: je ebb1x
|
; asm: je ebb1x
|
||||||
@@ -1082,6 +1132,7 @@ ebb1:
|
|||||||
; asm: ebb2x:
|
; asm: ebb2x:
|
||||||
ebb2:
|
ebb2:
|
||||||
jump ebb1 ; bin: eb fd
|
jump ebb1 ; bin: eb fd
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
; Tests for i32/i8 conversion instructions.
|
; Tests for i32/i8 conversion instructions.
|
||||||
@@ -1109,7 +1160,7 @@ ebb0:
|
|||||||
; asm: movzbl %r10b, %ecx
|
; asm: movzbl %r10b, %ecx
|
||||||
[-,%rcx] v32 = uextend.i32 v13 ; bin: 41 0f b6 ca
|
[-,%rcx] v32 = uextend.i32 v13 ; bin: 41 0f b6 ca
|
||||||
|
|
||||||
trap user0 ; bin: 0f 0b
|
trap user0 ; bin: user0 0f 0b
|
||||||
}
|
}
|
||||||
|
|
||||||
; Tests for i32/i16 conversion instructions.
|
; Tests for i32/i16 conversion instructions.
|
||||||
@@ -1137,7 +1188,7 @@ ebb0:
|
|||||||
; asm: movzwl %r10w, %ecx
|
; asm: movzwl %r10w, %ecx
|
||||||
[-,%rcx] v32 = uextend.i32 v13 ; bin: 41 0f b7 ca
|
[-,%rcx] v32 = uextend.i32 v13 ; bin: 41 0f b7 ca
|
||||||
|
|
||||||
trap user0 ; bin: 0f 0b
|
trap user0 ; bin: user0 0f 0b
|
||||||
}
|
}
|
||||||
|
|
||||||
; Tests for i64/i8 conversion instructions.
|
; Tests for i64/i8 conversion instructions.
|
||||||
@@ -1165,7 +1216,7 @@ ebb0:
|
|||||||
; asm: movzbl %r10b, %ecx
|
; asm: movzbl %r10b, %ecx
|
||||||
[-,%rcx] v32 = uextend.i64 v13 ; bin: 41 0f b6 ca
|
[-,%rcx] v32 = uextend.i64 v13 ; bin: 41 0f b6 ca
|
||||||
|
|
||||||
trap user0 ; bin: 0f 0b
|
trap user0 ; bin: user0 0f 0b
|
||||||
}
|
}
|
||||||
|
|
||||||
; Tests for i64/i16 conversion instructions.
|
; Tests for i64/i16 conversion instructions.
|
||||||
@@ -1193,7 +1244,7 @@ ebb0:
|
|||||||
; asm: movzwl %r10w, %ecx
|
; asm: movzwl %r10w, %ecx
|
||||||
[-,%rcx] v32 = uextend.i64 v13 ; bin: 41 0f b7 ca
|
[-,%rcx] v32 = uextend.i64 v13 ; bin: 41 0f b7 ca
|
||||||
|
|
||||||
trap user0 ; bin: 0f 0b
|
trap user0 ; bin: user0 0f 0b
|
||||||
}
|
}
|
||||||
|
|
||||||
; Tests for i64/i32 conversion instructions.
|
; Tests for i64/i32 conversion instructions.
|
||||||
@@ -1221,5 +1272,5 @@ ebb0:
|
|||||||
; asm: movl %r10d, %ecx
|
; asm: movl %r10d, %ecx
|
||||||
[-,%rcx] v32 = uextend.i64 v13 ; bin: 44 89 d1
|
[-,%rcx] v32 = uextend.i64 v13 ; bin: 44 89 d1
|
||||||
|
|
||||||
trap user0 ; bin: 0f 0b
|
trap user0 ; bin: user0 0f 0b
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ ebb0(v0: i64, v1: i64):
|
|||||||
; nextln: brif eq $fm1, $(m1=$EBB)
|
; nextln: brif eq $fm1, $(m1=$EBB)
|
||||||
; nextln: $(fz=$V) = ifcmp_imm v1, 0
|
; nextln: $(fz=$V) = ifcmp_imm v1, 0
|
||||||
; nextln: trapif eq $fz, int_divz
|
; nextln: trapif eq $fz, int_divz
|
||||||
; check: $(hi=$V) = sshr
|
; check: $(hi=$V) = sshr_imm
|
||||||
; nextln: $(q=$V), $(r=$V) = x86_sdivmodx v0, $hi, v1
|
; nextln: $(q=$V), $(r=$V) = x86_sdivmodx v0, $hi, v1
|
||||||
; nextln: jump $(done=$EBB)($q)
|
; nextln: jump $(done=$EBB)($q)
|
||||||
; check: $m1:
|
; check: $m1:
|
||||||
@@ -60,7 +60,7 @@ ebb0(v0: i64, v1: i64):
|
|||||||
v2 = srem v0, v1
|
v2 = srem v0, v1
|
||||||
; nextln: $(fm1=$V) = ifcmp_imm v1, -1
|
; nextln: $(fm1=$V) = ifcmp_imm v1, -1
|
||||||
; nextln: brif eq $fm1, $(m1=$EBB)
|
; nextln: brif eq $fm1, $(m1=$EBB)
|
||||||
; check: $(hi=$V) = sshr
|
; check: $(hi=$V) = sshr_imm
|
||||||
; nextln: $(d=$V), $(r=$V) = x86_sdivmodx v0, $hi, v1
|
; nextln: $(d=$V), $(r=$V) = x86_sdivmodx v0, $hi, v1
|
||||||
; nextln: jump $(done=$EBB)($r)
|
; nextln: jump $(done=$EBB)($r)
|
||||||
; check: $m1:
|
; check: $m1:
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ function %sdiv(i64, i64) -> i64 {
|
|||||||
ebb0(v0: i64, v1: i64):
|
ebb0(v0: i64, v1: i64):
|
||||||
; check: ebb0(
|
; check: ebb0(
|
||||||
v2 = sdiv v0, v1
|
v2 = sdiv v0, v1
|
||||||
; check: $(hi=$V) = sshr
|
; check: $(hi=$V) = sshr_imm
|
||||||
; nextln: $(d=$V), $(r=$V) = x86_sdivmodx v0, $hi, v1
|
; nextln: $(d=$V), $(r=$V) = x86_sdivmodx v0, $hi, v1
|
||||||
return v2
|
return v2
|
||||||
; nextln: return $d
|
; nextln: return $d
|
||||||
@@ -46,7 +46,7 @@ ebb0(v0: i64, v1: i64):
|
|||||||
v2 = srem v0, v1
|
v2 = srem v0, v1
|
||||||
; nextln: $(fm1=$V) = ifcmp_imm v1, -1
|
; nextln: $(fm1=$V) = ifcmp_imm v1, -1
|
||||||
; nextln: brif eq $fm1, $(m1=$EBB)
|
; nextln: brif eq $fm1, $(m1=$EBB)
|
||||||
; check: $(hi=$V) = sshr
|
; check: $(hi=$V) = sshr_imm
|
||||||
; nextln: $(d=$V), $(r=$V) = x86_sdivmodx v0, $hi, v1
|
; nextln: $(d=$V), $(r=$V) = x86_sdivmodx v0, $hi, v1
|
||||||
; nextln: jump $(done=$EBB)($r)
|
; nextln: jump $(done=$EBB)($r)
|
||||||
; check: $m1:
|
; check: $m1:
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ ebb0(v0: f32):
|
|||||||
v1 = floor v0
|
v1 = floor v0
|
||||||
return v1
|
return v1
|
||||||
}
|
}
|
||||||
; check: function %floor(f32 [%xmm0]) -> f32 [%xmm0] native {
|
; check: function %floor(f32 [%xmm0]) -> f32 [%xmm0] system_v {
|
||||||
; check: sig0 = (f32) -> f32 native
|
; check: sig0 = (f32) -> f32 system_v
|
||||||
; check: fn0 = sig0 %FloorF32
|
; check: fn0 = sig0 %FloorF32
|
||||||
; check: v1 = call fn0(v0)
|
; check: v1 = call fn0(v0)
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ function %deref(i64 vmctx) -> i64 {
|
|||||||
ebb1(v1: i64):
|
ebb1(v1: i64):
|
||||||
v2 = global_addr.i64 gv2
|
v2 = global_addr.i64 gv2
|
||||||
; check: $(a1=$V) = iadd_imm v1, -16
|
; check: $(a1=$V) = iadd_imm v1, -16
|
||||||
; check: $(p1=$V) = load.i64 $a1
|
; check: $(p1=$V) = load.i64 notrap aligned $a1
|
||||||
; check: v2 = iadd_imm $p1, 32
|
; check: v2 = iadd_imm $p1, 32
|
||||||
return v2
|
return v2
|
||||||
; check: return v2
|
; check: return v2
|
||||||
@@ -55,7 +55,7 @@ ebb0(v0: i32, v999: i64):
|
|||||||
; Checks here are assuming that no pipehole opts fold the load offsets.
|
; Checks here are assuming that no pipehole opts fold the load offsets.
|
||||||
; nextln: $(xoff=$V) = uextend.i64 v0
|
; nextln: $(xoff=$V) = uextend.i64 v0
|
||||||
; nextln: $(haddr=$V) = iadd_imm v999, 64
|
; nextln: $(haddr=$V) = iadd_imm v999, 64
|
||||||
; nextln: $(hbase=$V) = load.i64 $haddr
|
; nextln: $(hbase=$V) = load.i64 notrap aligned $haddr
|
||||||
; nextln: v1 = iadd $hbase, $xoff
|
; nextln: v1 = iadd $hbase, $xoff
|
||||||
v2 = load.f32 v1+16
|
v2 = load.f32 v1+16
|
||||||
; nextln: v2 = load.f32 v1+16
|
; nextln: v2 = load.f32 v1+16
|
||||||
@@ -103,7 +103,7 @@ ebb0(v0: i32, v999: i64):
|
|||||||
; Checks here are assuming that no pipehole opts fold the load offsets.
|
; Checks here are assuming that no pipehole opts fold the load offsets.
|
||||||
; nextln: $(xoff=$V) = uextend.i64 v0
|
; nextln: $(xoff=$V) = uextend.i64 v0
|
||||||
; nextln: $(haddr=$V) = iadd_imm.i64 v999, 64
|
; nextln: $(haddr=$V) = iadd_imm.i64 v999, 64
|
||||||
; nextln: $(hbase=$V) = load.i64 $haddr
|
; nextln: $(hbase=$V) = load.i64 notrap aligned $haddr
|
||||||
; nextln: v1 = iadd $hbase, $xoff
|
; nextln: v1 = iadd $hbase, $xoff
|
||||||
v2 = load.f32 v1+0x7fff_ffff
|
v2 = load.f32 v1+0x7fff_ffff
|
||||||
; nextln: v2 = load.f32 v1+0x7fff_ffff
|
; nextln: v2 = load.f32 v1+0x7fff_ffff
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ ebb0:
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
; check: function %foo(i64 fp [%rbp], i64 csr [%rbx], i64 csr [%r12], i64 csr [%r13], i64 csr [%r14], i64 csr [%r15]) -> i64 fp [%rbp], i64 csr [%rbx], i64 csr [%r12], i64 csr [%r13], i64 csr [%r14], i64 csr [%r15] native {
|
; check: function %foo(i64 fp [%rbp], i64 csr [%rbx], i64 csr [%r12], i64 csr [%r13], i64 csr [%r14], i64 csr [%r15]) -> i64 fp [%rbp], i64 csr [%rbx], i64 csr [%r12], i64 csr [%r13], i64 csr [%r14], i64 csr [%r15] system_v {
|
||||||
; nextln: ss0 = explicit_slot 168, offset -224
|
; nextln: ss0 = explicit_slot 168, offset -224
|
||||||
; nextln: ss1 = incoming_arg 56, offset -56
|
; nextln: ss1 = incoming_arg 56, offset -56
|
||||||
; check: ebb0(v0: i64 [%rbp], v1: i64 [%rbx], v2: i64 [%r12], v3: i64 [%r13], v4: i64 [%r14], v5: i64 [%r15]):
|
; check: ebb0(v0: i64 [%rbp], v1: i64 [%rbx], v2: i64 [%r12], v3: i64 [%r13], v4: i64 [%r14], v5: i64 [%r15]):
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ isa riscv enable_e
|
|||||||
function %f() {
|
function %f() {
|
||||||
; Spilling into the stack args after %x15 since %16 and up are not
|
; Spilling into the stack args after %x15 since %16 and up are not
|
||||||
; available in RV32E.
|
; available in RV32E.
|
||||||
sig0 = (i64, i64, i64, i64) -> i64 native
|
sig0 = (i64, i64, i64, i64) -> i64 system_v
|
||||||
; check: sig0 = (i32 [%x10], i32 [%x11], i32 [%x12], i32 [%x13], i32 [%x14], i32 [%x15], i32 [0], i32 [4]) -> i32 [%x10], i32 [%x11] native
|
; check: sig0 = (i32 [%x10], i32 [%x11], i32 [%x12], i32 [%x13], i32 [%x14], i32 [%x15], i32 [0], i32 [4]) -> i32 [%x10], i32 [%x11] system_v
|
||||||
ebb0:
|
ebb0:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,27 +5,27 @@ isa riscv
|
|||||||
; regex: V=v\d+
|
; regex: V=v\d+
|
||||||
|
|
||||||
function %f() {
|
function %f() {
|
||||||
sig0 = (i32) -> i32 native
|
sig0 = (i32) -> i32 system_v
|
||||||
; check: sig0 = (i32 [%x10]) -> i32 [%x10] native
|
; check: sig0 = (i32 [%x10]) -> i32 [%x10] system_v
|
||||||
|
|
||||||
sig1 = (i64) -> b1 native
|
sig1 = (i64) -> b1 system_v
|
||||||
; check: sig1 = (i32 [%x10], i32 [%x11]) -> b1 [%x10] native
|
; check: sig1 = (i32 [%x10], i32 [%x11]) -> b1 [%x10] system_v
|
||||||
|
|
||||||
; The i64 argument must go in an even-odd register pair.
|
; The i64 argument must go in an even-odd register pair.
|
||||||
sig2 = (f32, i64) -> f64 native
|
sig2 = (f32, i64) -> f64 system_v
|
||||||
; check: sig2 = (f32 [%f10], i32 [%x12], i32 [%x13]) -> f64 [%f10] native
|
; check: sig2 = (f32 [%f10], i32 [%x12], i32 [%x13]) -> f64 [%f10] system_v
|
||||||
|
|
||||||
; Spilling into the stack args.
|
; Spilling into the stack args.
|
||||||
sig3 = (f64, f64, f64, f64, f64, f64, f64, i64) -> f64 native
|
sig3 = (f64, f64, f64, f64, f64, f64, f64, i64) -> f64 system_v
|
||||||
; check: sig3 = (f64 [%f10], f64 [%f11], f64 [%f12], f64 [%f13], f64 [%f14], f64 [%f15], f64 [%f16], i32 [0], i32 [4]) -> f64 [%f10] native
|
; check: sig3 = (f64 [%f10], f64 [%f11], f64 [%f12], f64 [%f13], f64 [%f14], f64 [%f15], f64 [%f16], i32 [0], i32 [4]) -> f64 [%f10] system_v
|
||||||
|
|
||||||
; Splitting vectors.
|
; Splitting vectors.
|
||||||
sig4 = (i32x4) native
|
sig4 = (i32x4) system_v
|
||||||
; check: sig4 = (i32 [%x10], i32 [%x11], i32 [%x12], i32 [%x13]) native
|
; check: sig4 = (i32 [%x10], i32 [%x11], i32 [%x12], i32 [%x13]) system_v
|
||||||
|
|
||||||
; Splitting vectors, then splitting ints.
|
; Splitting vectors, then splitting ints.
|
||||||
sig5 = (i64x4) native
|
sig5 = (i64x4) system_v
|
||||||
; check: sig5 = (i32 [%x10], i32 [%x11], i32 [%x12], i32 [%x13], i32 [%x14], i32 [%x15], i32 [%x16], i32 [%x17]) native
|
; check: sig5 = (i32 [%x10], i32 [%x11], i32 [%x12], i32 [%x13], i32 [%x14], i32 [%x15], i32 [%x16], i32 [%x17]) system_v
|
||||||
|
|
||||||
ebb0:
|
ebb0:
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ ebb0(v0: i64x4):
|
|||||||
}
|
}
|
||||||
|
|
||||||
function %indirect(i32) {
|
function %indirect(i32) {
|
||||||
sig1 = () native
|
sig1 = () system_v
|
||||||
ebb0(v0: i32):
|
ebb0(v0: i32):
|
||||||
call_indirect sig1, v0()
|
call_indirect sig1, v0()
|
||||||
return
|
return
|
||||||
@@ -114,7 +114,7 @@ ebb0(v0: i32):
|
|||||||
|
|
||||||
; The first argument to call_indirect doesn't get altered.
|
; The first argument to call_indirect doesn't get altered.
|
||||||
function %indirect_arg(i32, f32x2) {
|
function %indirect_arg(i32, f32x2) {
|
||||||
sig1 = (f32x2) native
|
sig1 = (f32x2) system_v
|
||||||
ebb0(v0: i32, v1: f32x2):
|
ebb0(v0: i32, v1: f32x2):
|
||||||
call_indirect sig1, v0(v1)
|
call_indirect sig1, v0(v1)
|
||||||
; check: call_indirect sig1, v0($V, $V)
|
; check: call_indirect sig1, v0($V, $V)
|
||||||
|
|||||||
@@ -3,32 +3,32 @@ test legalizer
|
|||||||
isa riscv
|
isa riscv
|
||||||
|
|
||||||
function %parse_encoding(i32 [%x5]) -> i32 [%x10] {
|
function %parse_encoding(i32 [%x5]) -> i32 [%x10] {
|
||||||
; check: function %parse_encoding(i32 [%x5], i32 link [%x1]) -> i32 [%x10], i32 link [%x1] native {
|
; check: function %parse_encoding(i32 [%x5], i32 link [%x1]) -> i32 [%x10], i32 link [%x1] system_v {
|
||||||
|
|
||||||
sig0 = (i32 [%x10]) -> i32 [%x10] native
|
sig0 = (i32 [%x10]) -> i32 [%x10] system_v
|
||||||
; check: sig0 = (i32 [%x10]) -> i32 [%x10] native
|
; check: sig0 = (i32 [%x10]) -> i32 [%x10] system_v
|
||||||
|
|
||||||
sig1 = (i32 [%x10], i32 [%x11]) -> b1 [%x10] native
|
sig1 = (i32 [%x10], i32 [%x11]) -> b1 [%x10] system_v
|
||||||
; check: sig1 = (i32 [%x10], i32 [%x11]) -> b1 [%x10] native
|
; check: sig1 = (i32 [%x10], i32 [%x11]) -> b1 [%x10] system_v
|
||||||
|
|
||||||
sig2 = (f32 [%f10], i32 [%x12], i32 [%x13]) -> f64 [%f10] native
|
sig2 = (f32 [%f10], i32 [%x12], i32 [%x13]) -> f64 [%f10] system_v
|
||||||
; check: sig2 = (f32 [%f10], i32 [%x12], i32 [%x13]) -> f64 [%f10] native
|
; check: sig2 = (f32 [%f10], i32 [%x12], i32 [%x13]) -> f64 [%f10] system_v
|
||||||
|
|
||||||
; Arguments on stack where not necessary
|
; Arguments on stack where not necessary
|
||||||
sig3 = (f64 [%f10], i32 [0], i32 [4]) -> f64 [%f10] native
|
sig3 = (f64 [%f10], i32 [0], i32 [4]) -> f64 [%f10] system_v
|
||||||
; check: sig3 = (f64 [%f10], i32 [0], i32 [4]) -> f64 [%f10] native
|
; check: sig3 = (f64 [%f10], i32 [0], i32 [4]) -> f64 [%f10] system_v
|
||||||
|
|
||||||
; Stack argument before register argument
|
; Stack argument before register argument
|
||||||
sig4 = (f32 [72], i32 [%x10]) native
|
sig4 = (f32 [72], i32 [%x10]) system_v
|
||||||
; check: sig4 = (f32 [72], i32 [%x10]) native
|
; check: sig4 = (f32 [72], i32 [%x10]) system_v
|
||||||
|
|
||||||
; Return value on stack
|
; Return value on stack
|
||||||
sig5 = () -> f32 [0] native
|
sig5 = () -> f32 [0] system_v
|
||||||
; check: sig5 = () -> f32 [0] native
|
; check: sig5 = () -> f32 [0] system_v
|
||||||
|
|
||||||
; function + signature
|
; function + signature
|
||||||
fn0 = function %bar(i32 [%x10]) -> b1 [%x10] native
|
fn0 = function %bar(i32 [%x10]) -> b1 [%x10] system_v
|
||||||
; check: sig6 = (i32 [%x10]) -> b1 [%x10] native
|
; check: sig6 = (i32 [%x10]) -> b1 [%x10] system_v
|
||||||
; nextln: fn0 = sig6 %bar
|
; nextln: fn0 = sig6 %bar
|
||||||
|
|
||||||
ebb0(v0: i32):
|
ebb0(v0: i32):
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
test licm
|
test licm
|
||||||
|
|
||||||
function %complex(i32) -> i32 native {
|
function %complex(i32) -> i32 system_v {
|
||||||
ebb0(v0: i32):
|
ebb0(v0: i32):
|
||||||
jump ebb1(v0)
|
jump ebb1(v0)
|
||||||
|
|
||||||
|
|||||||
81
cranelift/filetests/licm/reject.cton
Normal file
81
cranelift/filetests/licm/reject.cton
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
test licm
|
||||||
|
|
||||||
|
function %other_side_effects(i32) -> i32 {
|
||||||
|
|
||||||
|
ebb0(v0: i32):
|
||||||
|
jump ebb1(v0)
|
||||||
|
|
||||||
|
ebb1(v1: i32):
|
||||||
|
regmove.i32 v0, %10 -> %20
|
||||||
|
; check: ebb1(v1: i32):
|
||||||
|
; check: regmove.i32 v0, %10 -> %20
|
||||||
|
v2 = iconst.i32 1
|
||||||
|
brz v1, ebb2(v1)
|
||||||
|
v5 = isub v1, v2
|
||||||
|
jump ebb1(v5)
|
||||||
|
|
||||||
|
ebb2(v6: i32):
|
||||||
|
return v6
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function %cpu_flags(i32, i32) -> i32 {
|
||||||
|
ebb0(v0: i32, v1: i32):
|
||||||
|
jump ebb1(v0, v1)
|
||||||
|
|
||||||
|
ebb1(v2: i32, v3: i32):
|
||||||
|
v4 = ifcmp.i32 v0, v1
|
||||||
|
v5 = selectif.i32 eq v4, v2, v3
|
||||||
|
; check: ebb1(v2: i32, v3: i32):
|
||||||
|
; check: ifcmp.i32 v0, v1
|
||||||
|
; check: v5 = selectif.i32 eq v4, v2, v3
|
||||||
|
v8 = iconst.i32 1
|
||||||
|
brz v1, ebb2(v1)
|
||||||
|
v9 = isub v1, v8
|
||||||
|
v10 = iadd v1, v8
|
||||||
|
jump ebb1(v9, v10)
|
||||||
|
|
||||||
|
ebb2(v6: i32):
|
||||||
|
return v6
|
||||||
|
}
|
||||||
|
|
||||||
|
function %spill(i32, i32) -> i32 {
|
||||||
|
ebb0(v0: i32, v1: i32):
|
||||||
|
v2 = spill.i32 v0
|
||||||
|
jump ebb1(v0, v1)
|
||||||
|
|
||||||
|
ebb1(v3: i32, v4: i32):
|
||||||
|
v5 = spill.i32 v1
|
||||||
|
v6 = fill.i32 v2
|
||||||
|
v7 = fill.i32 v5
|
||||||
|
; check: ebb1(v3: i32, v4: i32):
|
||||||
|
; check: v5 = spill.i32 v1
|
||||||
|
; check: v6 = fill.i32 v2
|
||||||
|
; check: v7 = fill v5
|
||||||
|
brz v1, ebb2(v1)
|
||||||
|
v9 = isub v1, v4
|
||||||
|
jump ebb1(v9, v3)
|
||||||
|
|
||||||
|
ebb2(v10: i32):
|
||||||
|
return v10
|
||||||
|
}
|
||||||
|
|
||||||
|
function %non_invariant_aliases(i32) -> i32 {
|
||||||
|
|
||||||
|
ebb0(v0: i32):
|
||||||
|
jump ebb1(v0)
|
||||||
|
|
||||||
|
ebb1(v1: i32):
|
||||||
|
v8 -> v1
|
||||||
|
v9 -> v1
|
||||||
|
v2 = iadd v8, v9
|
||||||
|
; check: ebb1(v1: i32):
|
||||||
|
; check: v2 = iadd v8, v9
|
||||||
|
brz v1, ebb2(v1)
|
||||||
|
v5 = isub v1, v2
|
||||||
|
jump ebb1(v5)
|
||||||
|
|
||||||
|
ebb2(v6: i32):
|
||||||
|
return v6
|
||||||
|
|
||||||
|
}
|
||||||
@@ -9,7 +9,7 @@ ebb0:
|
|||||||
ebb1:
|
ebb1:
|
||||||
jump ebb0()
|
jump ebb0()
|
||||||
}
|
}
|
||||||
; sameln: function %minimal() native {
|
; sameln: function %minimal() system_v {
|
||||||
; nextln: ebb0:
|
; nextln: ebb0:
|
||||||
; nextln: jump ebb1
|
; nextln: jump ebb1
|
||||||
; nextln:
|
; nextln:
|
||||||
@@ -25,7 +25,7 @@ ebb0(v90: i32):
|
|||||||
ebb1(v91: i32):
|
ebb1(v91: i32):
|
||||||
jump ebb0(v91)
|
jump ebb0(v91)
|
||||||
}
|
}
|
||||||
; sameln: function %onearg(i32) native {
|
; sameln: function %onearg(i32) system_v {
|
||||||
; nextln: ebb0(v90: i32):
|
; nextln: ebb0(v90: i32):
|
||||||
; nextln: jump ebb1(v90)
|
; nextln: jump ebb1(v90)
|
||||||
; nextln:
|
; nextln:
|
||||||
@@ -41,7 +41,7 @@ ebb0(v90: i32, v91: f32):
|
|||||||
ebb1(v92: i32, v93: f32):
|
ebb1(v92: i32, v93: f32):
|
||||||
jump ebb0(v92, v93)
|
jump ebb0(v92, v93)
|
||||||
}
|
}
|
||||||
; sameln: function %twoargs(i32, f32) native {
|
; sameln: function %twoargs(i32, f32) system_v {
|
||||||
; nextln: ebb0(v90: i32, v91: f32):
|
; nextln: ebb0(v90: i32, v91: f32):
|
||||||
; nextln: jump ebb1(v90, v91)
|
; nextln: jump ebb1(v90, v91)
|
||||||
; nextln:
|
; nextln:
|
||||||
@@ -57,7 +57,7 @@ ebb0(v90: i32):
|
|||||||
ebb1:
|
ebb1:
|
||||||
brnz v90, ebb1()
|
brnz v90, ebb1()
|
||||||
}
|
}
|
||||||
; sameln: function %minimal(i32) native {
|
; sameln: function %minimal(i32) system_v {
|
||||||
; nextln: ebb0(v90: i32):
|
; nextln: ebb0(v90: i32):
|
||||||
; nextln: brz v90, ebb1
|
; nextln: brz v90, ebb1
|
||||||
; nextln:
|
; nextln:
|
||||||
@@ -72,7 +72,7 @@ ebb0(v90: i32, v91: f32):
|
|||||||
ebb1(v92: i32, v93: f32):
|
ebb1(v92: i32, v93: f32):
|
||||||
brnz v90, ebb0(v92, v93)
|
brnz v90, ebb0(v92, v93)
|
||||||
}
|
}
|
||||||
; sameln: function %twoargs(i32, f32) native {
|
; sameln: function %twoargs(i32, f32) system_v {
|
||||||
; nextln: ebb0(v90: i32, v91: f32):
|
; nextln: ebb0(v90: i32, v91: f32):
|
||||||
; nextln: brz v90, ebb1(v90, v91)
|
; nextln: brz v90, ebb1(v90, v91)
|
||||||
; nextln:
|
; nextln:
|
||||||
@@ -94,7 +94,7 @@ ebb30:
|
|||||||
ebb40:
|
ebb40:
|
||||||
trap user4
|
trap user4
|
||||||
}
|
}
|
||||||
; sameln: function %jumptable(i32) native {
|
; sameln: function %jumptable(i32) system_v {
|
||||||
; check: jt2 = jump_table 0, 0, ebb10, ebb40, ebb20, ebb30
|
; check: jt2 = jump_table 0, 0, ebb10, ebb40, ebb20, ebb30
|
||||||
; check: jt200 = jump_table 0
|
; check: jt200 = jump_table 0
|
||||||
; check: ebb10(v3: i32):
|
; check: ebb10(v3: i32):
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ function %mini() {
|
|||||||
ebb1:
|
ebb1:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
; sameln: function %mini() native {
|
; sameln: function %mini() system_v {
|
||||||
; nextln: ebb1:
|
; nextln: ebb1:
|
||||||
; nextln: return
|
; nextln: return
|
||||||
; nextln: }
|
; nextln: }
|
||||||
@@ -29,10 +29,10 @@ function %signatures() {
|
|||||||
fn5 = sig11 %foo
|
fn5 = sig11 %foo
|
||||||
fn8 = function %bar(i32) -> b1
|
fn8 = function %bar(i32) -> b1
|
||||||
}
|
}
|
||||||
; sameln: function %signatures() native {
|
; sameln: function %signatures() system_v {
|
||||||
; check: sig10 = () native
|
; check: sig10 = () system_v
|
||||||
; check: sig11 = (i32, f64) -> i32, b1 spiderwasm
|
; check: sig11 = (i32, f64) -> i32, b1 spiderwasm
|
||||||
; check: sig12 = (i32) -> b1 native
|
; check: sig12 = (i32) -> b1 system_v
|
||||||
; not: fn0
|
; not: fn0
|
||||||
; check: fn5 = sig11 %foo
|
; check: fn5 = sig11 %foo
|
||||||
; check: fn8 = sig12 %bar
|
; check: fn8 = sig12 %bar
|
||||||
@@ -88,7 +88,7 @@ function %special1(i32 sret, i32 fp, i32 csr, i32 link) -> i32 link, i32 fp, i32
|
|||||||
ebb0(v1: i32, v2: i32, v3: i32, v4: i32):
|
ebb0(v1: i32, v2: i32, v3: i32, v4: i32):
|
||||||
return v4, v2, v3, v1
|
return v4, v2, v3, v1
|
||||||
}
|
}
|
||||||
; check: function %special1(i32 sret, i32 fp, i32 csr, i32 link) -> i32 link, i32 fp, i32 csr, i32 sret native {
|
; check: function %special1(i32 sret, i32 fp, i32 csr, i32 link) -> i32 link, i32 fp, i32 csr, i32 sret system_v {
|
||||||
; check: ebb0(v1: i32, v2: i32, v3: i32, v4: i32):
|
; check: ebb0(v1: i32, v2: i32, v3: i32, v4: i32):
|
||||||
; check: return v4, v2, v3, v1
|
; check: return v4, v2, v3, v1
|
||||||
; check: }
|
; check: }
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ ebb1(v0: i32 [%x8], v1: i32):
|
|||||||
@55 v9 = iadd v8, v7
|
@55 v9 = iadd v8, v7
|
||||||
@a5 [Iret#5] return v0, v8
|
@a5 [Iret#5] return v0, v8
|
||||||
}
|
}
|
||||||
; sameln: function %foo(i32, i32) native {
|
; sameln: function %foo(i32, i32) system_v {
|
||||||
; nextln: ebb1(v0: i32 [%x8], v1: i32):
|
; nextln: ebb1(v0: i32 [%x8], v1: i32):
|
||||||
; nextln: [-,-]$WS v2 = iadd v0, v1
|
; nextln: [-,-]$WS v2 = iadd v0, v1
|
||||||
; nextln: [-]$WS trap heap_oob
|
; nextln: [-]$WS trap heap_oob
|
||||||
|
|||||||
@@ -2,4 +2,4 @@ test cat
|
|||||||
|
|
||||||
; 'function' is not a keyword, and can be used as the name of a function too.
|
; 'function' is not a keyword, and can be used as the name of a function too.
|
||||||
function %function() {}
|
function %function() {}
|
||||||
; check: function %function() native
|
; check: function %function() system_v
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ ebb100(v20: i32):
|
|||||||
v9200 = f64const 0x4.0p0
|
v9200 = f64const 0x4.0p0
|
||||||
trap user4
|
trap user4
|
||||||
}
|
}
|
||||||
; sameln: function %defs() native {
|
; sameln: function %defs() system_v {
|
||||||
; nextln: ebb100(v20: i32):
|
; nextln: ebb100(v20: i32):
|
||||||
; nextln: v1000 = iconst.i32x8 5
|
; nextln: v1000 = iconst.i32x8 5
|
||||||
; nextln: v9200 = f64const 0x1.0000000000000p2
|
; nextln: v9200 = f64const 0x1.0000000000000p2
|
||||||
@@ -23,7 +23,7 @@ ebb100(v20: i32):
|
|||||||
v200 = iadd v20, v1000
|
v200 = iadd v20, v1000
|
||||||
jump ebb100(v1000)
|
jump ebb100(v1000)
|
||||||
}
|
}
|
||||||
; sameln: function %use_value() native {
|
; sameln: function %use_value() system_v {
|
||||||
; nextln: ebb100(v20: i32):
|
; nextln: ebb100(v20: i32):
|
||||||
; nextln: v1000 = iadd_imm v20, 5
|
; nextln: v1000 = iadd_imm v20, 5
|
||||||
; nextln: v200 = iadd v20, v1000
|
; nextln: v200 = iadd v20, v1000
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ function %minimal() {
|
|||||||
ebb0:
|
ebb0:
|
||||||
trap user0
|
trap user0
|
||||||
}
|
}
|
||||||
; sameln: function %minimal() native {
|
; sameln: function %minimal() system_v {
|
||||||
; nextln: ebb0:
|
; nextln: ebb0:
|
||||||
; nextln: trap user0
|
; nextln: trap user0
|
||||||
; nextln: }
|
; nextln: }
|
||||||
@@ -18,7 +18,7 @@ ebb0:
|
|||||||
v1 = iconst.i8 6
|
v1 = iconst.i8 6
|
||||||
v2 = ishl v0, v1
|
v2 = ishl v0, v1
|
||||||
}
|
}
|
||||||
; sameln: function %ivalues() native {
|
; sameln: function %ivalues() system_v {
|
||||||
; nextln: ebb0:
|
; nextln: ebb0:
|
||||||
; nextln: v0 = iconst.i32 2
|
; nextln: v0 = iconst.i32 2
|
||||||
; nextln: v1 = iconst.i8 6
|
; nextln: v1 = iconst.i8 6
|
||||||
@@ -34,7 +34,7 @@ ebb0:
|
|||||||
v2 = bextend.b32 v1
|
v2 = bextend.b32 v1
|
||||||
v3 = bxor v0, v2
|
v3 = bxor v0, v2
|
||||||
}
|
}
|
||||||
; sameln: function %bvalues() native {
|
; sameln: function %bvalues() system_v {
|
||||||
; nextln: ebb0:
|
; nextln: ebb0:
|
||||||
; nextln: v0 = bconst.b32 true
|
; nextln: v0 = bconst.b32 true
|
||||||
; nextln: v1 = bconst.b8 false
|
; nextln: v1 = bconst.b8 false
|
||||||
@@ -47,17 +47,17 @@ function %select() {
|
|||||||
ebb0(v90: i32, v91: i32, v92: b1):
|
ebb0(v90: i32, v91: i32, v92: b1):
|
||||||
v0 = select v92, v90, v91
|
v0 = select v92, v90, v91
|
||||||
}
|
}
|
||||||
; sameln: function %select() native {
|
; sameln: function %select() system_v {
|
||||||
; nextln: ebb0(v90: i32, v91: i32, v92: b1):
|
; nextln: ebb0(v90: i32, v91: i32, v92: b1):
|
||||||
; nextln: v0 = select v92, v90, v91
|
; nextln: v0 = select v92, v90, v91
|
||||||
; nextln: }
|
; nextln: }
|
||||||
|
|
||||||
; Polymorphic instruction controlled by third operand.
|
; Polymorphic instruction controlled by third operand.
|
||||||
function %selectif() native {
|
function %selectif() system_v {
|
||||||
ebb0(v95: i32, v96: i32, v97: b1):
|
ebb0(v95: i32, v96: i32, v97: b1):
|
||||||
v98 = selectif.i32 eq v97, v95, v96
|
v98 = selectif.i32 eq v97, v95, v96
|
||||||
}
|
}
|
||||||
; sameln: function %selectif() native {
|
; sameln: function %selectif() system_v {
|
||||||
; nextln: ebb0(v95: i32, v96: i32, v97: b1):
|
; nextln: ebb0(v95: i32, v96: i32, v97: b1):
|
||||||
; nextln: v98 = selectif.i32 eq v97, v95, v96
|
; nextln: v98 = selectif.i32 eq v97, v95, v96
|
||||||
; nextln: }
|
; nextln: }
|
||||||
@@ -69,7 +69,7 @@ ebb0:
|
|||||||
v1 = extractlane v0, 3
|
v1 = extractlane v0, 3
|
||||||
v2 = insertlane v0, 1, v1
|
v2 = insertlane v0, 1, v1
|
||||||
}
|
}
|
||||||
; sameln: function %lanes() native {
|
; sameln: function %lanes() system_v {
|
||||||
; nextln: ebb0:
|
; nextln: ebb0:
|
||||||
; nextln: v0 = iconst.i32x4 2
|
; nextln: v0 = iconst.i32x4 2
|
||||||
; nextln: v1 = extractlane v0, 3
|
; nextln: v1 = extractlane v0, 3
|
||||||
@@ -85,7 +85,7 @@ ebb0(v90: i32, v91: i32):
|
|||||||
v3 = irsub_imm v91, 45
|
v3 = irsub_imm v91, 45
|
||||||
br_icmp eq v90, v91, ebb0(v91, v90)
|
br_icmp eq v90, v91, ebb0(v91, v90)
|
||||||
}
|
}
|
||||||
; sameln: function %icmp(i32, i32) native {
|
; sameln: function %icmp(i32, i32) system_v {
|
||||||
; nextln: ebb0(v90: i32, v91: i32):
|
; nextln: ebb0(v90: i32, v91: i32):
|
||||||
; nextln: v0 = icmp eq v90, v91
|
; nextln: v0 = icmp eq v90, v91
|
||||||
; nextln: v1 = icmp ult v90, v91
|
; nextln: v1 = icmp ult v90, v91
|
||||||
@@ -101,7 +101,7 @@ ebb0(v90: f32, v91: f32):
|
|||||||
v1 = fcmp uno v90, v91
|
v1 = fcmp uno v90, v91
|
||||||
v2 = fcmp lt v90, v91
|
v2 = fcmp lt v90, v91
|
||||||
}
|
}
|
||||||
; sameln: function %fcmp(f32, f32) native {
|
; sameln: function %fcmp(f32, f32) system_v {
|
||||||
; nextln: ebb0(v90: f32, v91: f32):
|
; nextln: ebb0(v90: f32, v91: f32):
|
||||||
; nextln: v0 = fcmp eq v90, v91
|
; nextln: v0 = fcmp eq v90, v91
|
||||||
; nextln: v1 = fcmp uno v90, v91
|
; nextln: v1 = fcmp uno v90, v91
|
||||||
@@ -115,7 +115,7 @@ ebb0(v90: i32, v91: f32):
|
|||||||
v0 = bitcast.i8x4 v90
|
v0 = bitcast.i8x4 v90
|
||||||
v1 = bitcast.i32 v91
|
v1 = bitcast.i32 v91
|
||||||
}
|
}
|
||||||
; sameln: function %bitcast(i32, f32) native {
|
; sameln: function %bitcast(i32, f32) system_v {
|
||||||
; nextln: ebb0(v90: i32, v91: f32):
|
; nextln: ebb0(v90: i32, v91: f32):
|
||||||
; nextln: v0 = bitcast.i8x4 v90
|
; nextln: v0 = bitcast.i8x4 v90
|
||||||
; nextln: v1 = bitcast.i32 v91
|
; nextln: v1 = bitcast.i32 v91
|
||||||
@@ -135,7 +135,7 @@ ebb0:
|
|||||||
stack_store v1, ss10+2
|
stack_store v1, ss10+2
|
||||||
stack_store v2, ss2
|
stack_store v2, ss2
|
||||||
}
|
}
|
||||||
; sameln: function %stack() native {
|
; sameln: function %stack() system_v {
|
||||||
; check: ss2 = explicit_slot 4
|
; check: ss2 = explicit_slot 4
|
||||||
; check: ss3 = incoming_arg 4, offset 8
|
; check: ss3 = incoming_arg 4, offset 8
|
||||||
; check: ss4 = outgoing_arg 4
|
; check: ss4 = outgoing_arg 4
|
||||||
@@ -162,7 +162,7 @@ ebb0(v1: i32):
|
|||||||
store aligned v3, v1+12
|
store aligned v3, v1+12
|
||||||
store notrap aligned v3, v1-12
|
store notrap aligned v3, v1-12
|
||||||
}
|
}
|
||||||
; sameln: function %memory(i32) native {
|
; sameln: function %memory(i32) system_v {
|
||||||
; nextln: ebb0(v1: i32):
|
; nextln: ebb0(v1: i32):
|
||||||
; nextln: v2 = load.i64 v1
|
; nextln: v2 = load.i64 v1
|
||||||
; nextln: v3 = load.i64 aligned v1
|
; nextln: v3 = load.i64 aligned v1
|
||||||
@@ -187,7 +187,7 @@ ebb0(v1: i32):
|
|||||||
regfill v1, ss0 -> %10
|
regfill v1, ss0 -> %10
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
; sameln: function %diversion(i32) native {
|
; sameln: function %diversion(i32) system_v {
|
||||||
; nextln: ss0 = spill_slot 4
|
; nextln: ss0 = spill_slot 4
|
||||||
; check: ebb0(v1: i32):
|
; check: ebb0(v1: i32):
|
||||||
; nextln: regmove v1, %10 -> %20
|
; nextln: regmove v1, %10 -> %20
|
||||||
@@ -204,7 +204,7 @@ ebb0:
|
|||||||
copy_special %20 -> %10
|
copy_special %20 -> %10
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
; sameln: function %copy_special() native {
|
; sameln: function %copy_special() system_v {
|
||||||
; nextln: ebb0:
|
; nextln: ebb0:
|
||||||
; nextln: copy_special %10 -> %20
|
; nextln: copy_special %10 -> %20
|
||||||
; nextln: copy_special %20 -> %10
|
; nextln: copy_special %20 -> %10
|
||||||
|
|||||||
100
cranelift/filetests/postopt/basic.cton
Normal file
100
cranelift/filetests/postopt/basic.cton
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
test postopt
|
||||||
|
isa intel
|
||||||
|
|
||||||
|
; Test that compare+branch sequences are folded effectively on x86.
|
||||||
|
|
||||||
|
function %br_icmp(i32, i32) -> i32 {
|
||||||
|
ebb0(v0: i32, v1: i32):
|
||||||
|
[Op1icscc#39,%rdx] v2 = icmp slt v0, v1
|
||||||
|
[Op1t8jccd_long#85] brnz v2, ebb1
|
||||||
|
[Op1ret#c3] return v1
|
||||||
|
|
||||||
|
ebb1:
|
||||||
|
[Op1puid#b8,%rax] v8 = iconst.i32 3
|
||||||
|
[Op1ret#c3] return v8
|
||||||
|
}
|
||||||
|
; sameln: function %br_icmp
|
||||||
|
; nextln: ebb0(v0: i32, v1: i32):
|
||||||
|
; nextln: v9 = ifcmp v0, v1
|
||||||
|
; nextln: v2 = trueif slt v9
|
||||||
|
; nextln: brif slt v9, ebb1
|
||||||
|
; nextln: return v1
|
||||||
|
; nextln:
|
||||||
|
; nextln: ebb1:
|
||||||
|
; nextln: v8 = iconst.i32 3
|
||||||
|
; nextln: return v8
|
||||||
|
; nextln: }
|
||||||
|
|
||||||
|
; Use brz instead of brnz, so the condition is inverted.
|
||||||
|
|
||||||
|
function %br_icmp_inverse(i32, i32) -> i32 {
|
||||||
|
ebb0(v0: i32, v1: i32):
|
||||||
|
[Op1icscc#39,%rdx] v2 = icmp slt v0, v1
|
||||||
|
[Op1t8jccd_long#84] brz v2, ebb1
|
||||||
|
[Op1ret#c3] return v1
|
||||||
|
|
||||||
|
ebb1:
|
||||||
|
[Op1puid#b8,%rax] v8 = iconst.i32 3
|
||||||
|
[Op1ret#c3] return v8
|
||||||
|
}
|
||||||
|
; sameln: function %br_icmp_inverse
|
||||||
|
; nextln: ebb0(v0: i32, v1: i32):
|
||||||
|
; nextln: v9 = ifcmp v0, v1
|
||||||
|
; nextln: v2 = trueif slt v9
|
||||||
|
; nextln: brif sge v9, ebb1
|
||||||
|
; nextln: return v1
|
||||||
|
; nextln:
|
||||||
|
; nextln: ebb1:
|
||||||
|
; nextln: v8 = iconst.i32 3
|
||||||
|
; nextln: return v8
|
||||||
|
; nextln: }
|
||||||
|
|
||||||
|
; Use icmp_imm instead of icmp.
|
||||||
|
|
||||||
|
function %br_icmp_imm(i32, i32) -> i32 {
|
||||||
|
ebb0(v0: i32, v1: i32):
|
||||||
|
[Op1icsccib#7083] v2 = icmp_imm slt v0, 2
|
||||||
|
[Op1t8jccd_long#84] brz v2, ebb1
|
||||||
|
[Op1ret#c3] return v1
|
||||||
|
|
||||||
|
ebb1:
|
||||||
|
[Op1puid#b8,%rax] v8 = iconst.i32 3
|
||||||
|
[Op1ret#c3] return v8
|
||||||
|
}
|
||||||
|
; sameln: function %br_icmp_imm
|
||||||
|
; nextln: ebb0(v0: i32, v1: i32):
|
||||||
|
; nextln: v9 = ifcmp_imm v0, 2
|
||||||
|
; nextln: v2 = trueif slt v9
|
||||||
|
; nextln: brif sge v9, ebb1
|
||||||
|
; nextln: return v1
|
||||||
|
; nextln:
|
||||||
|
; nextln: ebb1:
|
||||||
|
; nextln: v8 = iconst.i32 3
|
||||||
|
; nextln: return v8
|
||||||
|
; nextln: }
|
||||||
|
|
||||||
|
; Use fcmp instead of icmp.
|
||||||
|
|
||||||
|
function %br_fcmp(f32, f32) -> f32 {
|
||||||
|
ebb0(v0: f32, v1: f32):
|
||||||
|
[Op2fcscc#42e,%rdx] v2 = fcmp gt v0, v1
|
||||||
|
[Op1t8jccd_long#84] brz v2, ebb1
|
||||||
|
[Op1ret#c3] return v1
|
||||||
|
|
||||||
|
ebb1:
|
||||||
|
[Op1puid#b8,%rax] v18 = iconst.i32 0x40a8_0000
|
||||||
|
[Mp2frurm#56e,%xmm0] v8 = bitcast.f32 v18
|
||||||
|
[Op1ret#c3] return v8
|
||||||
|
}
|
||||||
|
; sameln: function %br_fcmp
|
||||||
|
; nextln: ebb0(v0: f32, v1: f32):
|
||||||
|
; nextln: v19 = ffcmp v0, v1
|
||||||
|
; nextln: v2 = trueff gt v19
|
||||||
|
; nextln: brff ule v19, ebb1
|
||||||
|
; nextln: return v1
|
||||||
|
; nextln:
|
||||||
|
; nextln: ebb1:
|
||||||
|
; nextln: v18 = iconst.i32 0x40a8_0000
|
||||||
|
; nextln: v8 = bitcast.f32 v18
|
||||||
|
; nextln: return v8
|
||||||
|
; nextln: }
|
||||||
80
cranelift/filetests/preopt/simplify.cton
Normal file
80
cranelift/filetests/preopt/simplify.cton
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
test preopt
|
||||||
|
isa intel
|
||||||
|
|
||||||
|
function %iadd_imm(i32) -> i32 {
|
||||||
|
ebb0(v0: i32):
|
||||||
|
v1 = iconst.i32 2
|
||||||
|
v2 = iadd v0, v1
|
||||||
|
return v2
|
||||||
|
}
|
||||||
|
; sameln: function %iadd_imm
|
||||||
|
; nextln: ebb0(v0: i32):
|
||||||
|
; nextln: v1 = iconst.i32 2
|
||||||
|
; nextln: v2 = iadd_imm v0, 2
|
||||||
|
; nextln: return v2
|
||||||
|
; nextln: }
|
||||||
|
|
||||||
|
function %isub_imm(i32) -> i32 {
|
||||||
|
ebb0(v0: i32):
|
||||||
|
v1 = iconst.i32 2
|
||||||
|
v2 = isub v0, v1
|
||||||
|
return v2
|
||||||
|
}
|
||||||
|
; sameln: function %isub_imm
|
||||||
|
; nextln: ebb0(v0: i32):
|
||||||
|
; nextln: v1 = iconst.i32 2
|
||||||
|
; nextln: v2 = iadd_imm v0, -2
|
||||||
|
; nextln: return v2
|
||||||
|
; nextln: }
|
||||||
|
|
||||||
|
function %icmp_imm(i32) -> i32 {
|
||||||
|
ebb0(v0: i32):
|
||||||
|
v1 = iconst.i32 2
|
||||||
|
v2 = icmp slt v0, v1
|
||||||
|
v3 = bint.i32 v2
|
||||||
|
return v3
|
||||||
|
}
|
||||||
|
; sameln: function %icmp_imm
|
||||||
|
; nextln: ebb0(v0: i32):
|
||||||
|
; nextln: v1 = iconst.i32 2
|
||||||
|
; nextln: v2 = icmp_imm slt v0, 2
|
||||||
|
; nextln: v3 = bint.i32 v2
|
||||||
|
; nextln: return v3
|
||||||
|
; nextln: }
|
||||||
|
|
||||||
|
function %brz_bint(i32) {
|
||||||
|
ebb0(v0: i32):
|
||||||
|
v3 = icmp_imm slt v0, 0
|
||||||
|
v1 = bint.i32 v3
|
||||||
|
v2 = select v1, v1, v1
|
||||||
|
trapz v1, user0
|
||||||
|
brz v1, ebb1
|
||||||
|
jump ebb2
|
||||||
|
|
||||||
|
ebb1:
|
||||||
|
return
|
||||||
|
|
||||||
|
ebb2:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
; sameln: function %brz_bint
|
||||||
|
; nextln: (v0: i32):
|
||||||
|
; nextln: v3 = icmp_imm slt v0, 0
|
||||||
|
; nextln: v1 = bint.i32 v3
|
||||||
|
; nextln: v2 = select v3, v1, v1
|
||||||
|
; nextln: trapz v3, user0
|
||||||
|
; nextln: brz v3, ebb1
|
||||||
|
; nextln: jump ebb2
|
||||||
|
|
||||||
|
function %irsub_imm(i32) -> i32 {
|
||||||
|
ebb0(v0: i32):
|
||||||
|
v1 = iconst.i32 2
|
||||||
|
v2 = isub v1, v0
|
||||||
|
return v2
|
||||||
|
}
|
||||||
|
; sameln: function %irsub_imm
|
||||||
|
; nextln: ebb0(v0: i32):
|
||||||
|
; nextln: v1 = iconst.i32 2
|
||||||
|
; nextln: v2 = irsub_imm v1, 2
|
||||||
|
; nextln: return v2
|
||||||
|
; nextln: }
|
||||||
@@ -109,7 +109,7 @@ ebb1(v10: i32):
|
|||||||
return v11
|
return v11
|
||||||
}
|
}
|
||||||
|
|
||||||
function %gvn_unremovable_phi(i32) native {
|
function %gvn_unremovable_phi(i32) system_v {
|
||||||
ebb0(v0: i32):
|
ebb0(v0: i32):
|
||||||
v2 = iconst.i32 0
|
v2 = iconst.i32 0
|
||||||
jump ebb2(v2, v0)
|
jump ebb2(v2, v0)
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ isa intel haswell
|
|||||||
; Reported as https://github.com/Cretonne/cretonne/issues/207
|
; Reported as https://github.com/Cretonne/cretonne/issues/207
|
||||||
;
|
;
|
||||||
; The coalescer creates a virtual register with two interfering values.
|
; The coalescer creates a virtual register with two interfering values.
|
||||||
function %pr207(i64 vmctx, i32, i32) -> i32 native {
|
function %pr207(i64 vmctx, i32, i32) -> i32 system_v {
|
||||||
gv0 = vmctx-8
|
gv0 = vmctx-8
|
||||||
heap0 = static gv0, min 0, bound 0x5000, guard 0x0040_0000
|
heap0 = static gv0, min 0, bound 0x5000, guard 0x0040_0000
|
||||||
sig0 = (i64 vmctx, i32, i32) -> i32 native
|
sig0 = (i64 vmctx, i32, i32) -> i32 system_v
|
||||||
sig1 = (i64 vmctx, i32, i32, i32) -> i32 native
|
sig1 = (i64 vmctx, i32, i32, i32) -> i32 system_v
|
||||||
sig2 = (i64 vmctx, i32, i32, i32) -> i32 native
|
sig2 = (i64 vmctx, i32, i32, i32) -> i32 system_v
|
||||||
fn0 = sig0 u0:2
|
fn0 = sig0 u0:2
|
||||||
fn1 = sig1 u0:0
|
fn1 = sig1 u0:0
|
||||||
fn2 = sig2 u0:1
|
fn2 = sig2 u0:1
|
||||||
@@ -1034,10 +1034,10 @@ ebb92(v767: i32):
|
|||||||
}
|
}
|
||||||
|
|
||||||
; Same problem from musl.wasm.
|
; Same problem from musl.wasm.
|
||||||
function %musl(f64 [%xmm0], i64 vmctx [%rdi]) -> f64 [%xmm0] native {
|
function %musl(f64 [%xmm0], i64 vmctx [%rdi]) -> f64 [%xmm0] system_v {
|
||||||
gv0 = vmctx
|
gv0 = vmctx
|
||||||
heap0 = static gv0, min 0, bound 0x0001_0000_0000, guard 0x8000_0000
|
heap0 = static gv0, min 0, bound 0x0001_0000_0000, guard 0x8000_0000
|
||||||
sig0 = (f64 [%xmm0], i32 [%rdi], i64 vmctx [%rsi]) -> f64 [%xmm0] native
|
sig0 = (f64 [%xmm0], i32 [%rdi], i64 vmctx [%rsi]) -> f64 [%xmm0] system_v
|
||||||
fn0 = sig0 u0:517
|
fn0 = sig0 u0:517
|
||||||
|
|
||||||
ebb0(v0: f64, v1: i64):
|
ebb0(v0: f64, v1: i64):
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ isa intel haswell
|
|||||||
; Reported as https://github.com/Cretonne/cretonne/issues/216 from the Binaryen fuzzer.
|
; Reported as https://github.com/Cretonne/cretonne/issues/216 from the Binaryen fuzzer.
|
||||||
;
|
;
|
||||||
; The (old) coalescer creates a virtual register with two identical values.
|
; The (old) coalescer creates a virtual register with two identical values.
|
||||||
function %pr216(i32 [%rdi], i64 vmctx [%rsi]) -> i64 [%rax] native {
|
function %pr216(i32 [%rdi], i64 vmctx [%rsi]) -> i64 [%rax] system_v {
|
||||||
ebb0(v0: i32, v1: i64):
|
ebb0(v0: i32, v1: i64):
|
||||||
v3 = iconst.i64 0
|
v3 = iconst.i64 0
|
||||||
v5 = iconst.i32 0
|
v5 = iconst.i32 0
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ test regalloc
|
|||||||
set is_64bit
|
set is_64bit
|
||||||
isa intel haswell
|
isa intel haswell
|
||||||
|
|
||||||
function %pr227(i32 [%rdi], i32 [%rsi], i32 [%rdx], i32 [%rcx], i64 vmctx [%r8]) native {
|
function %pr227(i32 [%rdi], i32 [%rsi], i32 [%rdx], i32 [%rcx], i64 vmctx [%r8]) system_v {
|
||||||
gv0 = vmctx
|
gv0 = vmctx
|
||||||
heap0 = static gv0, min 0, bound 0x0001_0000_0000, guard 0x8000_0000
|
heap0 = static gv0, min 0, bound 0x0001_0000_0000, guard 0x8000_0000
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ function %pr227(i32 [%rdi], i32 [%rsi], i32 [%rdx], i32 [%rcx], i64 vmctx [%r8])
|
|||||||
@0011 [RexOp1puid#b8] v9 = iconst.i32 0
|
@0011 [RexOp1puid#b8] v9 = iconst.i32 0
|
||||||
@0015 [RexOp1puid#b8] v11 = iconst.i32 0
|
@0015 [RexOp1puid#b8] v11 = iconst.i32 0
|
||||||
@0017 [RexOp1icscc#39] v12 = icmp.i32 eq v15, v11
|
@0017 [RexOp1icscc#39] v12 = icmp.i32 eq v15, v11
|
||||||
@0017 [RexOp2urm#4b6] v13 = bint.i32 v12
|
@0017 [RexOp2urm_noflags#4b6] v13 = bint.i32 v12
|
||||||
@001a [RexOp1rr#21] v14 = band v9, v13
|
@001a [RexOp1rr#21] v14 = band v9, v13
|
||||||
@001b [RexOp1tjccb#75] brnz v14, ebb6
|
@001b [RexOp1tjccb#75] brnz v14, ebb6
|
||||||
@001d [RexOp1jmpb#eb] jump ebb7
|
@001d [RexOp1jmpb#eb] jump ebb7
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ isa intel haswell
|
|||||||
;
|
;
|
||||||
; Test case by binaryen fuzzer!
|
; Test case by binaryen fuzzer!
|
||||||
|
|
||||||
function %pr215(i64 vmctx [%rdi]) native {
|
function %pr215(i64 vmctx [%rdi]) system_v {
|
||||||
ebb0(v0: i64):
|
ebb0(v0: i64):
|
||||||
v10 = iconst.i64 0
|
v10 = iconst.i64 0
|
||||||
v1 = bitcast.f64 v10
|
v1 = bitcast.f64 v10
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ test regalloc
|
|||||||
set is_64bit=1
|
set is_64bit=1
|
||||||
isa intel haswell
|
isa intel haswell
|
||||||
|
|
||||||
function %foo() native {
|
function %foo() system_v {
|
||||||
ebb4:
|
ebb4:
|
||||||
v3 = iconst.i32 0
|
v3 = iconst.i32 0
|
||||||
jump ebb3
|
jump ebb3
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ isa intel
|
|||||||
; This ended up confusong the constraint solver which had not made a record of
|
; This ended up confusong the constraint solver which had not made a record of
|
||||||
; the fixed register assignment for v9 since it was already in the correct
|
; the fixed register assignment for v9 since it was already in the correct
|
||||||
; register.
|
; register.
|
||||||
function %pr147(i32) -> i32 native {
|
function %pr147(i32) -> i32 system_v {
|
||||||
ebb0(v0: i32):
|
ebb0(v0: i32):
|
||||||
v1 = iconst.i32 0
|
v1 = iconst.i32 0
|
||||||
v2 = iconst.i32 1
|
v2 = iconst.i32 1
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ test regalloc
|
|||||||
set is_64bit=1
|
set is_64bit=1
|
||||||
isa intel haswell
|
isa intel haswell
|
||||||
|
|
||||||
function %test(i64) -> i64 native {
|
function %test(i64) -> i64 system_v {
|
||||||
ebb0(v0: i64):
|
ebb0(v0: i64):
|
||||||
v2 = iconst.i64 12
|
v2 = iconst.i64 12
|
||||||
; This division clobbers two of its fixed input registers on Intel.
|
; This division clobbers two of its fixed input registers on Intel.
|
||||||
|
|||||||
@@ -11,11 +11,11 @@ isa intel haswell
|
|||||||
;
|
;
|
||||||
; The problem was the reload pass rewriting EBB arguments on "brnz v9, ebb3(v9)"
|
; The problem was the reload pass rewriting EBB arguments on "brnz v9, ebb3(v9)"
|
||||||
|
|
||||||
function %pr208(i64 vmctx [%rdi]) native {
|
function %pr208(i64 vmctx [%rdi]) system_v {
|
||||||
gv0 = vmctx-8
|
gv0 = vmctx-8
|
||||||
heap0 = static gv0, min 0, bound 0x5000, guard 0x0040_0000
|
heap0 = static gv0, min 0, bound 0x5000, guard 0x0040_0000
|
||||||
sig0 = (i64 vmctx [%rdi]) -> i32 [%rax] native
|
sig0 = (i64 vmctx [%rdi]) -> i32 [%rax] system_v
|
||||||
sig1 = (i64 vmctx [%rdi], i32 [%rsi]) native
|
sig1 = (i64 vmctx [%rdi], i32 [%rsi]) system_v
|
||||||
fn0 = sig0 u0:1
|
fn0 = sig0 u0:1
|
||||||
fn1 = sig1 u0:3
|
fn1 = sig1 u0:3
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ isa riscv enable_e
|
|||||||
|
|
||||||
; Check that we can handle a function return value that got spilled.
|
; Check that we can handle a function return value that got spilled.
|
||||||
function %spill_return() -> i32 {
|
function %spill_return() -> i32 {
|
||||||
fn0 = function %foo() -> i32 native
|
fn0 = function %foo() -> i32 system_v
|
||||||
|
|
||||||
ebb0:
|
ebb0:
|
||||||
v0 = call fn0()
|
v0 = call fn0()
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
test regalloc
|
test regalloc
|
||||||
isa intel haswell
|
isa intel haswell
|
||||||
|
|
||||||
function %pr165() native {
|
function %pr165() system_v {
|
||||||
ebb0:
|
ebb0:
|
||||||
v0 = iconst.i32 0x0102_0304
|
v0 = iconst.i32 0x0102_0304
|
||||||
v1 = iconst.i32 0x1102_0304
|
v1 = iconst.i32 0x1102_0304
|
||||||
@@ -19,7 +19,7 @@ ebb0:
|
|||||||
|
|
||||||
; Same as above, but use so many registers that spilling is required.
|
; Same as above, but use so many registers that spilling is required.
|
||||||
; Note: This is also a candidate for using xchg instructions.
|
; Note: This is also a candidate for using xchg instructions.
|
||||||
function %emergency_spill() native {
|
function %emergency_spill() system_v {
|
||||||
ebb0:
|
ebb0:
|
||||||
v0 = iconst.i32 0x0102_0304
|
v0 = iconst.i32 0x0102_0304
|
||||||
v1 = iconst.i32 0x1102_0304
|
v1 = iconst.i32 0x1102_0304
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ isa intel
|
|||||||
;
|
;
|
||||||
; The spiller was not releasing register pressure for dead EBB parameters.
|
; The spiller was not releasing register pressure for dead EBB parameters.
|
||||||
|
|
||||||
function %pr223(i32 [%rdi], i64 vmctx [%rsi]) -> i64 [%rax] native {
|
function %pr223(i32 [%rdi], i64 vmctx [%rsi]) -> i64 [%rax] system_v {
|
||||||
ebb0(v0: i32, v1: i64):
|
ebb0(v0: i32, v1: i64):
|
||||||
v2 = iconst.i32 0
|
v2 = iconst.i32 0
|
||||||
v3 = iconst.i64 0
|
v3 = iconst.i64 0
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ ebb0(v0: i32):
|
|||||||
|
|
||||||
; The same value used as indirect callee and argument.
|
; The same value used as indirect callee and argument.
|
||||||
function %doubleuse_icall1(i32) {
|
function %doubleuse_icall1(i32) {
|
||||||
sig0 = (i32) native
|
sig0 = (i32) system_v
|
||||||
ebb0(v0: i32):
|
ebb0(v0: i32):
|
||||||
; not:copy
|
; not:copy
|
||||||
call_indirect sig0, v0(v0)
|
call_indirect sig0, v0(v0)
|
||||||
@@ -102,7 +102,7 @@ ebb0(v0: i32):
|
|||||||
|
|
||||||
; The same value used as indirect callee and two arguments.
|
; The same value used as indirect callee and two arguments.
|
||||||
function %doubleuse_icall2(i32) {
|
function %doubleuse_icall2(i32) {
|
||||||
sig0 = (i32, i32) native
|
sig0 = (i32, i32) system_v
|
||||||
ebb0(v0: i32):
|
ebb0(v0: i32):
|
||||||
; check: $(c=$V) = copy v0
|
; check: $(c=$V) = copy v0
|
||||||
call_indirect sig0, v0(v0, v0)
|
call_indirect sig0, v0(v0, v0)
|
||||||
|
|||||||
16
cranelift/filetests/verifier/defs_dominates_uses.cton
Normal file
16
cranelift/filetests/verifier/defs_dominates_uses.cton
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
test verifier
|
||||||
|
|
||||||
|
; Test verification that uses properly dominate defs.
|
||||||
|
|
||||||
|
function %non_dominating(i32) -> i32 system_v {
|
||||||
|
ebb0(v0: i32):
|
||||||
|
v1 = iadd.i32 v2, v0 ; error: uses value from non-dominating
|
||||||
|
v2 = iadd.i32 v1, v0
|
||||||
|
return v2
|
||||||
|
}
|
||||||
|
|
||||||
|
function %inst_uses_its_own_values(i32) -> i32 system_v {
|
||||||
|
ebb0(v0: i32):
|
||||||
|
v1 = iadd.i32 v1, v0 ; error: uses value from itself
|
||||||
|
return v1
|
||||||
|
}
|
||||||
@@ -6,7 +6,7 @@ function %simple(i32) -> i32 {
|
|||||||
ebb0(v0: i32):
|
ebb0(v0: i32):
|
||||||
[Op1rcmp#39] v1 = ifcmp v0, v0
|
[Op1rcmp#39] v1 = ifcmp v0, v0
|
||||||
[Op2seti_abcd#490] v2 = trueif ugt v1
|
[Op2seti_abcd#490] v2 = trueif ugt v1
|
||||||
[Op2urm_abcd#4b6] v3 = bint.i32 v2
|
[Op2urm_noflags_abcd#4b6] v3 = bint.i32 v2
|
||||||
[Op1ret#c3] return v3
|
[Op1ret#c3] return v3
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ function %overlap(i32, f32) -> i32 {
|
|||||||
[Op2setf_abcd#490] v4 = trueff gt v3 ; error: conflicting live CPU flags: v2 and v3
|
[Op2setf_abcd#490] v4 = trueff gt v3 ; error: conflicting live CPU flags: v2 and v3
|
||||||
[Op2seti_abcd#490] v5 = trueif ugt v2
|
[Op2seti_abcd#490] v5 = trueif ugt v2
|
||||||
[Op1rr#21] v6 = band v4, v5
|
[Op1rr#21] v6 = band v4, v5
|
||||||
[Op2urm_abcd#4b6] v7 = bint.i32 v6
|
[Op2urm_noflags_abcd#4b6] v7 = bint.i32 v6
|
||||||
[Op1ret#c3] return v7
|
[Op1ret#c3] return v7
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ function %clobbered(i32) -> i32 {
|
|||||||
[Op1rcmp#39] v1 = ifcmp v0, v0
|
[Op1rcmp#39] v1 = ifcmp v0, v0
|
||||||
[Op1rr#01] v2 = iadd v0, v0 ; error: encoding clobbers live CPU flags in v1
|
[Op1rr#01] v2 = iadd v0, v0 ; error: encoding clobbers live CPU flags in v1
|
||||||
[Op2seti_abcd#490] v3 = trueif ugt v1
|
[Op2seti_abcd#490] v3 = trueif ugt v1
|
||||||
[Op2urm_abcd#4b6] v4 = bint.i32 v3
|
[Op2urm_noflags_abcd#4b6] v4 = bint.i32 v3
|
||||||
[Op1ret#c3] return v4
|
[Op1ret#c3] return v4
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ function %live_across_load(i32) -> i32 {
|
|||||||
[Op1rcmp#39] v1 = ifcmp v0, v0
|
[Op1rcmp#39] v1 = ifcmp v0, v0
|
||||||
[Op1ld#8b] v2 = load.i32 v0
|
[Op1ld#8b] v2 = load.i32 v0
|
||||||
[Op2seti_abcd#490] v3 = trueif ugt v1
|
[Op2seti_abcd#490] v3 = trueif ugt v1
|
||||||
[Op2urm_abcd#4b6] v4 = bint.i32 v3
|
[Op2urm_noflags_abcd#4b6] v4 = bint.i32 v3
|
||||||
[Op1ret#c3] return v4
|
[Op1ret#c3] return v4
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ function %live_across_ebb(i32) -> i32 {
|
|||||||
[Op1jmpb#eb] jump ebb1
|
[Op1jmpb#eb] jump ebb1
|
||||||
ebb1:
|
ebb1:
|
||||||
[Op2seti_abcd#490] v2 = trueif ugt v1
|
[Op2seti_abcd#490] v2 = trueif ugt v1
|
||||||
[Op2urm_abcd#4b6] v3 = bint.i32 v2
|
[Op2urm_noflags_abcd#4b6] v3 = bint.i32 v2
|
||||||
[Op1ret#c3] return v3
|
[Op1ret#c3] return v3
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@ function %live_across_ebb_backwards(i32) -> i32 {
|
|||||||
[Op1jmpb#eb] jump ebb2
|
[Op1jmpb#eb] jump ebb2
|
||||||
ebb1:
|
ebb1:
|
||||||
[Op2seti_abcd#490] v2 = trueif ugt v1
|
[Op2seti_abcd#490] v2 = trueif ugt v1
|
||||||
[Op2urm_abcd#4b6] v3 = bint.i32 v2
|
[Op2urm_noflags_abcd#4b6] v3 = bint.i32 v2
|
||||||
[Op1ret#c3] return v3
|
[Op1ret#c3] return v3
|
||||||
ebb2:
|
ebb2:
|
||||||
[Op1rcmp#39] v1 = ifcmp v0, v0
|
[Op1rcmp#39] v1 = ifcmp v0, v0
|
||||||
|
|||||||
@@ -4,17 +4,13 @@ cd $(dirname "$0")
|
|||||||
topdir="$(pwd)"
|
topdir="$(pwd)"
|
||||||
|
|
||||||
# All the cretonne-* crates have the same version number
|
# All the cretonne-* crates have the same version number
|
||||||
# The filecheck crate version is managed independently.
|
version="0.4.1"
|
||||||
version="0.3.4"
|
|
||||||
|
|
||||||
# Update all of the Cargo.toml files.
|
# Update all of the Cargo.toml files.
|
||||||
#
|
#
|
||||||
# The main Cargo.toml in the top-level directory is the cretonne-tools crate which we don't publish.
|
# The main Cargo.toml in the top-level directory is the cretonne-tools crate which we don't publish.
|
||||||
echo "Updating crate versions to $version"
|
echo "Updating crate versions to $version"
|
||||||
for crate in . lib/*; do
|
for crate in . lib/*; do
|
||||||
if [ "$crate" = "lib/filecheck" ]; then
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
# Update the version number of this crate to $version.
|
# Update the version number of this crate to $version.
|
||||||
sed -i.bk -e "s/^version = .*/version = \"$version\"/" "$crate/Cargo.toml"
|
sed -i.bk -e "s/^version = .*/version = \"$version\"/" "$crate/Cargo.toml"
|
||||||
# Update the required version number of any cretonne* dependencies.
|
# Update the required version number of any cretonne* dependencies.
|
||||||
@@ -31,7 +27,7 @@ cargo update
|
|||||||
|
|
||||||
echo git commit -a -m "\"Bump version to $version"\"
|
echo git commit -a -m "\"Bump version to $version"\"
|
||||||
echo git push
|
echo git push
|
||||||
for crate in filecheck cretonne frontend native reader wasm; do
|
for crate in cretonne frontend native reader wasm; do
|
||||||
echo cargo publish --manifest-path "lib/$crate/Cargo.toml"
|
echo cargo publish --manifest-path "lib/$crate/Cargo.toml"
|
||||||
done
|
done
|
||||||
echo
|
echo
|
||||||
|
|||||||
@@ -1,16 +1,13 @@
|
|||||||
//! The `cat` sub-command.
|
//! The `cat` sub-command.
|
||||||
//!
|
//!
|
||||||
//! Read a sequence of Cretonne IL files and print them again to stdout. This has the effect of
|
//! Read a sequence of Cretonne IR files and print them again to stdout. This has the effect of
|
||||||
//! normalizing formatting and removing comments.
|
//! normalizing formatting and removing comments.
|
||||||
|
|
||||||
use std::borrow::Cow;
|
|
||||||
use cretonne::ir::Function;
|
|
||||||
use cton_reader::{parse_functions, TestCommand};
|
|
||||||
use CommandResult;
|
use CommandResult;
|
||||||
|
use cton_reader::parse_functions;
|
||||||
use utils::read_to_string;
|
use utils::read_to_string;
|
||||||
use filetest::subtest::{self, SubTest, Context, Result as STResult};
|
|
||||||
|
|
||||||
pub fn run(files: Vec<String>) -> CommandResult {
|
pub fn run(files: &[String]) -> CommandResult {
|
||||||
for (i, f) in files.into_iter().enumerate() {
|
for (i, f) in files.into_iter().enumerate() {
|
||||||
if i != 0 {
|
if i != 0 {
|
||||||
println!();
|
println!();
|
||||||
@@ -20,7 +17,7 @@ pub fn run(files: Vec<String>) -> CommandResult {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cat_one(filename: String) -> CommandResult {
|
fn cat_one(filename: &str) -> CommandResult {
|
||||||
let buffer = read_to_string(&filename).map_err(
|
let buffer = read_to_string(&filename).map_err(
|
||||||
|e| format!("{}: {}", filename, e),
|
|e| format!("{}: {}", filename, e),
|
||||||
)?;
|
)?;
|
||||||
@@ -37,34 +34,3 @@ fn cat_one(filename: String) -> CommandResult {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Object implementing the `test cat` sub-test.
|
|
||||||
///
|
|
||||||
/// This command is used for testing the parser and function printer. It simply parses a function
|
|
||||||
/// and prints it out again.
|
|
||||||
///
|
|
||||||
/// The result is verified by filecheck.
|
|
||||||
struct TestCat;
|
|
||||||
|
|
||||||
pub fn subtest(parsed: &TestCommand) -> STResult<Box<SubTest>> {
|
|
||||||
assert_eq!(parsed.command, "cat");
|
|
||||||
if !parsed.options.is_empty() {
|
|
||||||
Err(format!("No options allowed on {}", parsed))
|
|
||||||
} else {
|
|
||||||
Ok(Box::new(TestCat))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SubTest for TestCat {
|
|
||||||
fn name(&self) -> Cow<str> {
|
|
||||||
Cow::from("cat")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn needs_verifier(&self) -> bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(&self, func: Cow<Function>, context: &Context) -> STResult<()> {
|
|
||||||
subtest::run_filecheck(&func.display(context.isa).to_string(), context)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
//! CLI tool to compile cretonne IL into native code.
|
//! CLI tool to read Cretonne IR files and compile them into native code.
|
||||||
//!
|
|
||||||
//! Reads IR files into Cretonne IL and compiles it.
|
|
||||||
|
|
||||||
use cton_reader::parse_test;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
use cretonne::Context;
|
use cretonne::Context;
|
||||||
|
use cretonne::print_errors::pretty_error;
|
||||||
use cretonne::settings::FlagsOrIsa;
|
use cretonne::settings::FlagsOrIsa;
|
||||||
use cretonne::{binemit, ir};
|
use cretonne::{binemit, ir};
|
||||||
|
use cton_reader::parse_test;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use utils::{pretty_error, read_to_string, parse_sets_and_isa};
|
use std::path::PathBuf;
|
||||||
|
use utils::{parse_sets_and_isa, read_to_string};
|
||||||
|
|
||||||
struct PrintRelocs {
|
struct PrintRelocs {
|
||||||
flag_print: bool,
|
flag_print: bool,
|
||||||
@@ -45,26 +44,38 @@ impl binemit::RelocSink for PrintRelocs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct PrintTraps {
|
||||||
|
flag_print: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl binemit::TrapSink for PrintTraps {
|
||||||
|
fn trap(&mut self, offset: binemit::CodeOffset, _srcloc: ir::SourceLoc, code: ir::TrapCode) {
|
||||||
|
if self.flag_print {
|
||||||
|
println!("trap: {} at {}", code, offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn run(
|
pub fn run(
|
||||||
files: Vec<String>,
|
files: Vec<String>,
|
||||||
flag_print: bool,
|
flag_print: bool,
|
||||||
flag_set: Vec<String>,
|
flag_set: &[String],
|
||||||
flag_isa: String,
|
flag_isa: &str,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
let parsed = parse_sets_and_isa(flag_set, flag_isa)?;
|
let parsed = parse_sets_and_isa(flag_set, flag_isa)?;
|
||||||
|
|
||||||
for filename in files {
|
for filename in files {
|
||||||
let path = Path::new(&filename);
|
let path = Path::new(&filename);
|
||||||
let name = String::from(path.as_os_str().to_string_lossy());
|
let name = String::from(path.as_os_str().to_string_lossy());
|
||||||
handle_module(flag_print, path.to_path_buf(), name, parsed.as_fisa())?;
|
handle_module(flag_print, &path.to_path_buf(), &name, parsed.as_fisa())?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_module(
|
fn handle_module(
|
||||||
flag_print: bool,
|
flag_print: bool,
|
||||||
path: PathBuf,
|
path: &PathBuf,
|
||||||
name: String,
|
name: &str,
|
||||||
fisa: FlagsOrIsa,
|
fisa: FlagsOrIsa,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
let buffer = read_to_string(&path).map_err(
|
let buffer = read_to_string(&path).map_err(
|
||||||
@@ -95,8 +106,9 @@ fn handle_module(
|
|||||||
// Encode the result as machine code.
|
// Encode the result as machine code.
|
||||||
let mut mem = Vec::new();
|
let mut mem = Vec::new();
|
||||||
let mut relocs = PrintRelocs { flag_print };
|
let mut relocs = PrintRelocs { flag_print };
|
||||||
|
let mut traps = PrintTraps { flag_print };
|
||||||
mem.resize(size as usize, 0);
|
mem.resize(size as usize, 0);
|
||||||
context.emit_to_memory(mem.as_mut_ptr(), &mut relocs, &*isa);
|
context.emit_to_memory(mem.as_mut_ptr(), &mut relocs, &mut traps, &*isa);
|
||||||
|
|
||||||
if flag_print {
|
if flag_print {
|
||||||
print!(".byte ");
|
print!(".byte ");
|
||||||
|
|||||||
@@ -1,27 +1,25 @@
|
|||||||
#[macro_use(dbg)]
|
|
||||||
extern crate cretonne;
|
extern crate cretonne;
|
||||||
|
extern crate cton_filetests;
|
||||||
extern crate cton_reader;
|
extern crate cton_reader;
|
||||||
extern crate cton_wasm;
|
extern crate cton_wasm;
|
||||||
extern crate docopt;
|
extern crate docopt;
|
||||||
|
extern crate filecheck;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde_derive;
|
extern crate serde_derive;
|
||||||
extern crate filecheck;
|
|
||||||
extern crate num_cpus;
|
|
||||||
extern crate tempdir;
|
extern crate tempdir;
|
||||||
extern crate term;
|
extern crate term;
|
||||||
|
|
||||||
use cretonne::{VERSION, timing};
|
use cretonne::{timing, VERSION};
|
||||||
use docopt::Docopt;
|
use docopt::Docopt;
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
use std::process;
|
use std::process;
|
||||||
|
|
||||||
mod utils;
|
|
||||||
mod filetest;
|
|
||||||
mod cat;
|
mod cat;
|
||||||
|
mod compile;
|
||||||
mod print_cfg;
|
mod print_cfg;
|
||||||
mod rsfilecheck;
|
mod rsfilecheck;
|
||||||
|
mod utils;
|
||||||
mod wasm;
|
mod wasm;
|
||||||
mod compile;
|
|
||||||
|
|
||||||
const USAGE: &str = "
|
const USAGE: &str = "
|
||||||
Cretonne code generator utility
|
Cretonne code generator utility
|
||||||
@@ -40,12 +38,12 @@ Options:
|
|||||||
-T, --time-passes
|
-T, --time-passes
|
||||||
print pass timing report
|
print pass timing report
|
||||||
-t, --just-decode
|
-t, --just-decode
|
||||||
just decode WebAssembly to Cretonne IL
|
just decode WebAssembly to Cretonne IR
|
||||||
-s, --print-size
|
-s, --print-size
|
||||||
prints generated code size
|
prints generated code size
|
||||||
-c, --check-translation
|
-c, --check-translation
|
||||||
just checks the correctness of Cretonne IL translated from WebAssembly
|
just checks the correctness of Cretonne IR translated from WebAssembly
|
||||||
-p, --print print the resulting Cretonne IL
|
-p, --print print the resulting Cretonne IR
|
||||||
-h, --help print this help message
|
-h, --help print this help message
|
||||||
--set=<set> configure Cretonne settings
|
--set=<set> configure Cretonne settings
|
||||||
--isa=<isa> specify the Cretonne ISA
|
--isa=<isa> specify the Cretonne ISA
|
||||||
@@ -88,15 +86,20 @@ fn cton_util() -> CommandResult {
|
|||||||
|
|
||||||
// Find the sub-command to execute.
|
// Find the sub-command to execute.
|
||||||
let result = if args.cmd_test {
|
let result = if args.cmd_test {
|
||||||
filetest::run(args.flag_verbose, args.arg_file)
|
cton_filetests::run(args.flag_verbose, &args.arg_file).map(|_time| ())
|
||||||
} else if args.cmd_cat {
|
} else if args.cmd_cat {
|
||||||
cat::run(args.arg_file)
|
cat::run(&args.arg_file)
|
||||||
} else if args.cmd_filecheck {
|
} else if args.cmd_filecheck {
|
||||||
rsfilecheck::run(args.arg_file, args.flag_verbose)
|
rsfilecheck::run(&args.arg_file, args.flag_verbose)
|
||||||
} else if args.cmd_print_cfg {
|
} else if args.cmd_print_cfg {
|
||||||
print_cfg::run(args.arg_file)
|
print_cfg::run(&args.arg_file)
|
||||||
} else if args.cmd_compile {
|
} else if args.cmd_compile {
|
||||||
compile::run(args.arg_file, args.flag_print, args.flag_set, args.flag_isa)
|
compile::run(
|
||||||
|
args.arg_file,
|
||||||
|
args.flag_print,
|
||||||
|
&args.flag_set,
|
||||||
|
&args.flag_isa,
|
||||||
|
)
|
||||||
} else if args.cmd_wasm {
|
} else if args.cmd_wasm {
|
||||||
wasm::run(
|
wasm::run(
|
||||||
args.arg_file,
|
args.arg_file,
|
||||||
@@ -104,8 +107,8 @@ fn cton_util() -> CommandResult {
|
|||||||
args.flag_just_decode,
|
args.flag_just_decode,
|
||||||
args.flag_check_translation,
|
args.flag_check_translation,
|
||||||
args.flag_print,
|
args.flag_print,
|
||||||
args.flag_set,
|
&args.flag_set,
|
||||||
args.flag_isa,
|
&args.flag_isa,
|
||||||
args.flag_print_size,
|
args.flag_print_size,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,75 +0,0 @@
|
|||||||
//! File tests.
|
|
||||||
//!
|
|
||||||
//! This module contains the main driver for `cton-util test` as well as implementations of the
|
|
||||||
//! available test commands.
|
|
||||||
|
|
||||||
use std::path::Path;
|
|
||||||
use std::time;
|
|
||||||
use cton_reader::TestCommand;
|
|
||||||
use CommandResult;
|
|
||||||
use cat;
|
|
||||||
use print_cfg;
|
|
||||||
use filetest::runner::TestRunner;
|
|
||||||
|
|
||||||
pub mod subtest;
|
|
||||||
|
|
||||||
mod binemit;
|
|
||||||
mod compile;
|
|
||||||
mod concurrent;
|
|
||||||
mod domtree;
|
|
||||||
mod legalizer;
|
|
||||||
mod licm;
|
|
||||||
mod preopt;
|
|
||||||
mod regalloc;
|
|
||||||
mod runner;
|
|
||||||
mod runone;
|
|
||||||
mod simple_gvn;
|
|
||||||
mod verifier;
|
|
||||||
|
|
||||||
/// The result of running the test in a file.
|
|
||||||
pub type TestResult = Result<time::Duration, String>;
|
|
||||||
|
|
||||||
/// Main entry point for `cton-util test`.
|
|
||||||
///
|
|
||||||
/// Take a list of filenames which can be either `.cton` files or directories.
|
|
||||||
///
|
|
||||||
/// Files are interpreted as test cases and executed immediately.
|
|
||||||
///
|
|
||||||
/// Directories are scanned recursively for test cases ending in `.cton`. These test cases are
|
|
||||||
/// executed on background threads.
|
|
||||||
///
|
|
||||||
pub fn run(verbose: bool, files: Vec<String>) -> CommandResult {
|
|
||||||
let mut runner = TestRunner::new(verbose);
|
|
||||||
|
|
||||||
for path in files.iter().map(Path::new) {
|
|
||||||
if path.is_file() {
|
|
||||||
runner.push_test(path);
|
|
||||||
} else {
|
|
||||||
runner.push_dir(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
runner.start_threads();
|
|
||||||
runner.run()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a new subcommand trait object to match `parsed.command`.
|
|
||||||
///
|
|
||||||
/// This function knows how to create all of the possible `test <foo>` commands that can appear in
|
|
||||||
/// a `.cton` test file.
|
|
||||||
fn new_subtest(parsed: &TestCommand) -> subtest::Result<Box<subtest::SubTest>> {
|
|
||||||
match parsed.command {
|
|
||||||
"binemit" => binemit::subtest(parsed),
|
|
||||||
"cat" => cat::subtest(parsed),
|
|
||||||
"compile" => compile::subtest(parsed),
|
|
||||||
"domtree" => domtree::subtest(parsed),
|
|
||||||
"legalizer" => legalizer::subtest(parsed),
|
|
||||||
"licm" => licm::subtest(parsed),
|
|
||||||
"preopt" => preopt::subtest(parsed),
|
|
||||||
"print-cfg" => print_cfg::subtest(parsed),
|
|
||||||
"regalloc" => regalloc::subtest(parsed),
|
|
||||||
"simple-gvn" => simple_gvn::subtest(parsed),
|
|
||||||
"verifier" => verifier::subtest(parsed),
|
|
||||||
_ => Err(format!("unknown test command '{}'", parsed.command)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,20 +1,14 @@
|
|||||||
//! The `print-cfg` sub-command.
|
//! The `print-cfg` sub-command.
|
||||||
//!
|
//!
|
||||||
//! Read a series of Cretonne IL files and print their control flow graphs
|
//! Read a series of Cretonne IR files and print their control flow graphs
|
||||||
//! in graphviz format.
|
//! in graphviz format.
|
||||||
|
|
||||||
use std::borrow::Cow;
|
|
||||||
use std::fmt::{Result, Write, Display, Formatter};
|
|
||||||
|
|
||||||
use CommandResult;
|
use CommandResult;
|
||||||
use cretonne::flowgraph::ControlFlowGraph;
|
use cretonne::cfg_printer::CFGPrinter;
|
||||||
use cretonne::ir::Function;
|
use cton_reader::parse_functions;
|
||||||
use cretonne::ir::instructions::BranchInfo;
|
|
||||||
use cton_reader::{parse_functions, TestCommand};
|
|
||||||
use filetest::subtest::{self, SubTest, Context, Result as STResult};
|
|
||||||
use utils::read_to_string;
|
use utils::read_to_string;
|
||||||
|
|
||||||
pub fn run(files: Vec<String>) -> CommandResult {
|
pub fn run(files: &[String]) -> CommandResult {
|
||||||
for (i, f) in files.into_iter().enumerate() {
|
for (i, f) in files.into_iter().enumerate() {
|
||||||
if i != 0 {
|
if i != 0 {
|
||||||
println!();
|
println!();
|
||||||
@@ -24,74 +18,8 @@ pub fn run(files: Vec<String>) -> CommandResult {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CFGPrinter<'a> {
|
fn print_cfg(filename: &str) -> CommandResult {
|
||||||
func: &'a Function,
|
let buffer = read_to_string(filename).map_err(
|
||||||
cfg: ControlFlowGraph,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> CFGPrinter<'a> {
|
|
||||||
pub fn new(func: &'a Function) -> CFGPrinter<'a> {
|
|
||||||
CFGPrinter {
|
|
||||||
func,
|
|
||||||
cfg: ControlFlowGraph::with_function(func),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Write the CFG for this function to `w`.
|
|
||||||
pub fn write(&self, w: &mut Write) -> Result {
|
|
||||||
self.header(w)?;
|
|
||||||
self.ebb_nodes(w)?;
|
|
||||||
self.cfg_connections(w)?;
|
|
||||||
writeln!(w, "}}")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn header(&self, w: &mut Write) -> Result {
|
|
||||||
writeln!(w, "digraph \"{}\" {{", self.func.name)?;
|
|
||||||
if let Some(entry) = self.func.layout.entry_block() {
|
|
||||||
writeln!(w, " {{rank=min; {}}}", entry)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ebb_nodes(&self, w: &mut Write) -> Result {
|
|
||||||
for ebb in &self.func.layout {
|
|
||||||
write!(w, " {} [shape=record, label=\"{{{}", ebb, ebb)?;
|
|
||||||
// Add all outgoing branch instructions to the label.
|
|
||||||
for inst in self.func.layout.ebb_insts(ebb) {
|
|
||||||
let idata = &self.func.dfg[inst];
|
|
||||||
match idata.analyze_branch(&self.func.dfg.value_lists) {
|
|
||||||
BranchInfo::SingleDest(dest, _) => {
|
|
||||||
write!(w, " | <{}>{} {}", inst, idata.opcode(), dest)?
|
|
||||||
}
|
|
||||||
BranchInfo::Table(table) => {
|
|
||||||
write!(w, " | <{}>{} {}", inst, idata.opcode(), table)?
|
|
||||||
}
|
|
||||||
BranchInfo::NotABranch => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
writeln!(w, "}}\"]")?
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cfg_connections(&self, w: &mut Write) -> Result {
|
|
||||||
for ebb in &self.func.layout {
|
|
||||||
for (parent, inst) in self.cfg.pred_iter(ebb) {
|
|
||||||
writeln!(w, " {}:{} -> {}", parent, inst, ebb)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Display for CFGPrinter<'a> {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> Result {
|
|
||||||
self.write(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn print_cfg(filename: String) -> CommandResult {
|
|
||||||
let buffer = read_to_string(&filename).map_err(
|
|
||||||
|e| format!("{}: {}", filename, e),
|
|e| format!("{}: {}", filename, e),
|
||||||
)?;
|
)?;
|
||||||
let items = parse_functions(&buffer).map_err(
|
let items = parse_functions(&buffer).map_err(
|
||||||
@@ -107,29 +35,3 @@ fn print_cfg(filename: String) -> CommandResult {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Object implementing the `test print-cfg` sub-test.
|
|
||||||
struct TestPrintCfg;
|
|
||||||
|
|
||||||
pub fn subtest(parsed: &TestCommand) -> STResult<Box<SubTest>> {
|
|
||||||
assert_eq!(parsed.command, "print-cfg");
|
|
||||||
if !parsed.options.is_empty() {
|
|
||||||
Err(format!("No options allowed on {}", parsed))
|
|
||||||
} else {
|
|
||||||
Ok(Box::new(TestPrintCfg))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SubTest for TestPrintCfg {
|
|
||||||
fn name(&self) -> Cow<str> {
|
|
||||||
Cow::from("print-cfg")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn needs_verifier(&self) -> bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(&self, func: Cow<Function>, context: &Context) -> STResult<()> {
|
|
||||||
subtest::run_filecheck(&CFGPrinter::new(&func).to_string(), context)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
use CommandResult;
|
//! The `filecheck` sub-command.
|
||||||
use utils::read_to_string;
|
//!
|
||||||
use filecheck::{CheckerBuilder, Checker, NO_VARIABLES};
|
//! This file is named to avoid a name collision with the filecheck crate.
|
||||||
use std::io::{self, Read};
|
|
||||||
|
|
||||||
pub fn run(files: Vec<String>, verbose: bool) -> CommandResult {
|
use CommandResult;
|
||||||
|
use filecheck::{Checker, CheckerBuilder, NO_VARIABLES};
|
||||||
|
use std::io::{self, Read};
|
||||||
|
use utils::read_to_string;
|
||||||
|
|
||||||
|
pub fn run(files: &[String], verbose: bool) -> CommandResult {
|
||||||
if files.is_empty() {
|
if files.is_empty() {
|
||||||
return Err("No check files".to_string());
|
return Err("No check files".to_string());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
//! Utility functions.
|
//! Utility functions.
|
||||||
|
|
||||||
use cretonne::ir::entities::AnyEntity;
|
use cretonne::isa;
|
||||||
use cretonne::{ir, verifier};
|
|
||||||
use cretonne::result::CtonError;
|
|
||||||
use cretonne::isa::TargetIsa;
|
use cretonne::isa::TargetIsa;
|
||||||
use cretonne::settings::{self, FlagsOrIsa};
|
use cretonne::settings::{self, FlagsOrIsa};
|
||||||
use cretonne::isa;
|
|
||||||
use cton_reader::{parse_options, Location};
|
use cton_reader::{parse_options, Location};
|
||||||
use std::fmt::Write;
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{self, Read};
|
use std::io::{self, Read};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
@@ -28,51 +24,6 @@ pub fn read_to_end<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
|
|||||||
Ok(buffer)
|
Ok(buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Look for a directive in a comment string.
|
|
||||||
/// The directive is of the form "foo:" and should follow the leading `;` in the comment:
|
|
||||||
///
|
|
||||||
/// ; dominates: ebb3 ebb4
|
|
||||||
///
|
|
||||||
/// Return the comment text following the directive.
|
|
||||||
pub fn match_directive<'a>(comment: &'a str, directive: &str) -> Option<&'a str> {
|
|
||||||
assert!(
|
|
||||||
directive.ends_with(':'),
|
|
||||||
"Directive must include trailing colon"
|
|
||||||
);
|
|
||||||
let text = comment.trim_left_matches(';').trim_left();
|
|
||||||
if text.starts_with(directive) {
|
|
||||||
Some(text[directive.len()..].trim())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pretty-print a verifier error.
|
|
||||||
pub fn pretty_verifier_error(
|
|
||||||
func: &ir::Function,
|
|
||||||
isa: Option<&TargetIsa>,
|
|
||||||
err: verifier::Error,
|
|
||||||
) -> String {
|
|
||||||
let mut msg = err.to_string();
|
|
||||||
match err.location {
|
|
||||||
AnyEntity::Inst(inst) => {
|
|
||||||
write!(msg, "\n{}: {}\n\n", inst, func.dfg.display_inst(inst, isa)).unwrap()
|
|
||||||
}
|
|
||||||
_ => msg.push('\n'),
|
|
||||||
}
|
|
||||||
write!(msg, "{}", func.display(isa)).unwrap();
|
|
||||||
msg
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pretty-print a Cretonne error.
|
|
||||||
pub fn pretty_error(func: &ir::Function, isa: Option<&TargetIsa>, err: CtonError) -> String {
|
|
||||||
if let CtonError::Verifier(e) = err {
|
|
||||||
pretty_verifier_error(func, isa, e)
|
|
||||||
} else {
|
|
||||||
err.to_string()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Like `FlagsOrIsa`, but holds ownership.
|
/// Like `FlagsOrIsa`, but holds ownership.
|
||||||
pub enum OwnedFlagsOrIsa {
|
pub enum OwnedFlagsOrIsa {
|
||||||
Flags(settings::Flags),
|
Flags(settings::Flags),
|
||||||
@@ -90,10 +41,7 @@ impl OwnedFlagsOrIsa {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Parse "set" and "isa" commands.
|
/// Parse "set" and "isa" commands.
|
||||||
pub fn parse_sets_and_isa(
|
pub fn parse_sets_and_isa(flag_set: &[String], flag_isa: &str) -> Result<OwnedFlagsOrIsa, String> {
|
||||||
flag_set: Vec<String>,
|
|
||||||
flag_isa: String,
|
|
||||||
) -> Result<OwnedFlagsOrIsa, String> {
|
|
||||||
let mut flag_builder = settings::builder();
|
let mut flag_builder = settings::builder();
|
||||||
parse_options(
|
parse_options(
|
||||||
flag_set.iter().map(|x| x.as_str()),
|
flag_set.iter().map(|x| x.as_str()),
|
||||||
@@ -119,12 +67,3 @@ pub fn parse_sets_and_isa(
|
|||||||
Ok(OwnedFlagsOrIsa::Flags(settings::Flags::new(&flag_builder)))
|
Ok(OwnedFlagsOrIsa::Flags(settings::Flags::new(&flag_builder)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_match_directive() {
|
|
||||||
assert_eq!(match_directive("; foo: bar ", "foo:"), Some("bar"));
|
|
||||||
assert_eq!(match_directive(" foo:bar", "foo:"), Some("bar"));
|
|
||||||
assert_eq!(match_directive("foo:bar", "foo:"), Some("bar"));
|
|
||||||
assert_eq!(match_directive(";x foo: bar", "foo:"), None);
|
|
||||||
assert_eq!(match_directive(";;; foo: bar", "foo:"), Some("bar"));
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,19 +1,21 @@
|
|||||||
//! CLI tool to use the functions provided by the [cretonne-wasm](../cton_wasm/index.html) crate.
|
//! CLI tool to use the functions provided by the [cretonne-wasm](../cton_wasm/index.html) crate.
|
||||||
//!
|
//!
|
||||||
//! Reads Wasm binary files, translates the functions' code to Cretonne IL.
|
//! Reads Wasm binary files, translates the functions' code to Cretonne IR.
|
||||||
|
#![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments, cyclomatic_complexity))]
|
||||||
|
|
||||||
use cton_wasm::{translate_module, DummyEnvironment, ModuleEnvironment};
|
|
||||||
use std::path::PathBuf;
|
|
||||||
use cretonne::Context;
|
use cretonne::Context;
|
||||||
|
use cretonne::print_errors::{pretty_error, pretty_verifier_error};
|
||||||
use cretonne::settings::FlagsOrIsa;
|
use cretonne::settings::FlagsOrIsa;
|
||||||
use std::fs::File;
|
use cton_wasm::{translate_module, DummyEnvironment, ModuleEnvironment};
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
use std::fs::File;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use tempdir::TempDir;
|
use tempdir::TempDir;
|
||||||
use term;
|
use term;
|
||||||
use utils::{pretty_verifier_error, pretty_error, parse_sets_and_isa, read_to_end};
|
use utils::{parse_sets_and_isa, read_to_end};
|
||||||
|
|
||||||
macro_rules! vprintln {
|
macro_rules! vprintln {
|
||||||
($x: expr, $($tts:tt)*) => {
|
($x: expr, $($tts:tt)*) => {
|
||||||
@@ -37,8 +39,8 @@ pub fn run(
|
|||||||
flag_just_decode: bool,
|
flag_just_decode: bool,
|
||||||
flag_check_translation: bool,
|
flag_check_translation: bool,
|
||||||
flag_print: bool,
|
flag_print: bool,
|
||||||
flag_set: Vec<String>,
|
flag_set: &[String],
|
||||||
flag_isa: String,
|
flag_isa: &str,
|
||||||
flag_print_size: bool,
|
flag_print_size: bool,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
let parsed = parse_sets_and_isa(flag_set, flag_isa)?;
|
let parsed = parse_sets_and_isa(flag_set, flag_isa)?;
|
||||||
@@ -52,8 +54,8 @@ pub fn run(
|
|||||||
flag_check_translation,
|
flag_check_translation,
|
||||||
flag_print,
|
flag_print,
|
||||||
flag_print_size,
|
flag_print_size,
|
||||||
path.to_path_buf(),
|
&path.to_path_buf(),
|
||||||
name,
|
&name,
|
||||||
parsed.as_fisa(),
|
parsed.as_fisa(),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
@@ -66,8 +68,8 @@ fn handle_module(
|
|||||||
flag_check_translation: bool,
|
flag_check_translation: bool,
|
||||||
flag_print: bool,
|
flag_print: bool,
|
||||||
flag_print_size: bool,
|
flag_print_size: bool,
|
||||||
path: PathBuf,
|
path: &PathBuf,
|
||||||
name: String,
|
name: &str,
|
||||||
fisa: FlagsOrIsa,
|
fisa: FlagsOrIsa,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
let mut terminal = term::stdout().unwrap();
|
let mut terminal = term::stdout().unwrap();
|
||||||
@@ -152,10 +154,9 @@ fn handle_module(
|
|||||||
context.func = func.clone();
|
context.func = func.clone();
|
||||||
if flag_check_translation {
|
if flag_check_translation {
|
||||||
context.verify(fisa).map_err(|err| {
|
context.verify(fisa).map_err(|err| {
|
||||||
pretty_verifier_error(&context.func, fisa.isa, err)
|
pretty_verifier_error(&context.func, fisa.isa, &err)
|
||||||
})?;
|
})?;
|
||||||
} else {
|
} else if let Some(isa) = fisa.isa {
|
||||||
if let Some(isa) = fisa.isa {
|
|
||||||
let compiled_size = context.compile(isa).map_err(|err| {
|
let compiled_size = context.compile(isa).map_err(|err| {
|
||||||
pretty_error(&context.func, fisa.isa, err)
|
pretty_error(&context.func, fisa.isa, err)
|
||||||
})?;
|
})?;
|
||||||
@@ -169,13 +170,12 @@ fn handle_module(
|
|||||||
println!(
|
println!(
|
||||||
"Function #{} bytecode size: {} bytes",
|
"Function #{} bytecode size: {} bytes",
|
||||||
func_index,
|
func_index,
|
||||||
dummy_environ.func_bytecode_sizes[func_index]
|
dummy_environ.func_bytecode_sizes[def_index]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(String::from("compilation requires a target isa"));
|
return Err(String::from("compilation requires a target isa"));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if flag_print {
|
if flag_print {
|
||||||
vprintln!(flag_verbose, "");
|
vprintln!(flag_verbose, "");
|
||||||
if let Some(start_func) = dummy_environ.info.start_func {
|
if let Some(start_func) = dummy_environ.info.start_func {
|
||||||
@@ -193,10 +193,7 @@ fn handle_module(
|
|||||||
|
|
||||||
if !flag_check_translation && flag_print_size {
|
if !flag_check_translation && flag_print_size {
|
||||||
println!("Total module code size: {} bytes", total_module_code_size);
|
println!("Total module code size: {} bytes", total_module_code_size);
|
||||||
let total_bytecode_size = dummy_environ.func_bytecode_sizes.iter().fold(
|
let total_bytecode_size: usize = dummy_environ.func_bytecode_sizes.iter().sum();
|
||||||
0,
|
|
||||||
|sum, x| sum + x,
|
|
||||||
);
|
|
||||||
println!("Total module bytecode size: {} bytes", total_bytecode_size);
|
println!("Total module bytecode size: {} bytes", total_bytecode_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,11 +3,10 @@ set -euo pipefail
|
|||||||
|
|
||||||
# This is the top-level test script:
|
# This is the top-level test script:
|
||||||
#
|
#
|
||||||
# - Build documentation for Rust code in 'src/tools/target/doc'.
|
# - Make a debug build.
|
||||||
# - Run unit tests for all Rust crates.
|
# - Make a release build.
|
||||||
# - Make a debug build of all crates.
|
# - Run unit tests for all Rust crates (including the filetests)
|
||||||
# - Make a release build of cton-util.
|
# - Build API documentation.
|
||||||
# - Run file-level tests with the release build of cton-util.
|
|
||||||
#
|
#
|
||||||
# All tests run by this script should be passing at all times.
|
# All tests run by this script should be passing at all times.
|
||||||
|
|
||||||
@@ -42,22 +41,26 @@ if [ -n "$needcheck" ]; then
|
|||||||
touch $tsfile || echo no target directory
|
touch $tsfile || echo no target directory
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cd "$topdir"
|
# Make sure the code builds in debug mode.
|
||||||
banner "Rust unit tests"
|
banner "Rust debug build"
|
||||||
cargo test --all
|
cargo build
|
||||||
|
|
||||||
# Build cton-util for parser testing.
|
# Make sure the code builds in release mode, and run the unit tests. We run
|
||||||
cd "$topdir"
|
# these in release mode for speed, but note that the top-level Cargo.toml file
|
||||||
banner "Rust documentation"
|
# does enable debug assertions in release builds.
|
||||||
echo "open $topdir/target/doc/cretonne/index.html"
|
banner "Rust release build and unit tests"
|
||||||
|
cargo test --all --release
|
||||||
|
|
||||||
|
# Make sure the documentation builds.
|
||||||
|
banner "Rust documentation: $topdir/target/doc/cretonne/index.html"
|
||||||
cargo doc
|
cargo doc
|
||||||
banner "Rust release build"
|
|
||||||
cargo build --release
|
|
||||||
|
|
||||||
export CTONUTIL="$topdir/target/release/cton-util"
|
# Run clippy if we have it.
|
||||||
|
banner "Rust linter"
|
||||||
cd "$topdir"
|
if $topdir/check-clippy.sh; then
|
||||||
banner "File tests"
|
$topdir/clippy-all.sh --write-mode=diff
|
||||||
"$CTONUTIL" test filetests docs
|
else
|
||||||
|
echo "\`cargo +nightly install clippy\` for optional rust linting"
|
||||||
|
fi
|
||||||
|
|
||||||
banner "OK"
|
banner "OK"
|
||||||
|
|||||||
7
cranelift/tests/filetests.rs
Normal file
7
cranelift/tests/filetests.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
extern crate cton_filetests;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn filetests() {
|
||||||
|
// Run all the filetests in the following directories.
|
||||||
|
cton_filetests::run(false, &["filetests".into(), "docs".into()]).expect("test harness");
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
authors = ["The Cretonne Project Developers"]
|
authors = ["The Cretonne Project Developers"]
|
||||||
name = "cretonne"
|
name = "cretonne"
|
||||||
version = "0.3.4"
|
version = "0.4.1"
|
||||||
description = "Low-level code generator library"
|
description = "Low-level code generator library"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
documentation = "https://cretonne.readthedocs.io/"
|
documentation = "https://cretonne.readthedocs.io/"
|
||||||
@@ -32,3 +32,7 @@ optional = true
|
|||||||
default = ["std"]
|
default = ["std"]
|
||||||
std = []
|
std = []
|
||||||
core = ["hashmap_core"]
|
core = ["hashmap_core"]
|
||||||
|
|
||||||
|
[badges]
|
||||||
|
maintenance = { status = "experimental" }
|
||||||
|
travis-ci = { repository = "Cretonne/cretonne" }
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
This crate contains the core Cretonne code generator. It translates code from an
|
This crate contains the core Cretonne code generator. It translates code from an
|
||||||
intermediate language into executable machine code.
|
intermediate representation into executable machine code.
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
// The build script expects to be run from the directory where this build.rs file lives. The
|
// The build script expects to be run from the directory where this build.rs file lives. The
|
||||||
// current directory is used to find the sources.
|
// current directory is used to find the sources.
|
||||||
|
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::process;
|
use std::process;
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
The cretonne.formats defines all instruction formats.
|
The cretonne.formats defines all instruction formats.
|
||||||
|
|
||||||
Every instruction format has a corresponding `InstructionData` variant in the
|
Every instruction format has a corresponding `InstructionData` variant in the
|
||||||
Rust representation of cretonne IL, so all instruction formats must be defined
|
Rust representation of Cretonne IR, so all instruction formats must be defined
|
||||||
in this module.
|
in this module.
|
||||||
"""
|
"""
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
|
|||||||
@@ -588,6 +588,9 @@ stack_check = Instruction(
|
|||||||
Read the stack limit from ``GV`` and compare it to the stack pointer. If
|
Read the stack limit from ``GV`` and compare it to the stack pointer. If
|
||||||
the stack pointer has reached or exceeded the limit, generate a trap with a
|
the stack pointer has reached or exceeded the limit, generate a trap with a
|
||||||
``stk_ovf`` code.
|
``stk_ovf`` code.
|
||||||
|
|
||||||
|
The global variable must be accessible and naturally aligned for a
|
||||||
|
pointer-sized value.
|
||||||
""",
|
""",
|
||||||
ins=GV, can_trap=True)
|
ins=GV, can_trap=True)
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ widen = XFormGroup('widen', """
|
|||||||
|
|
||||||
The transformations in the 'widen' group work by expressing
|
The transformations in the 'widen' group work by expressing
|
||||||
instructions in terms of larger types.
|
instructions in terms of larger types.
|
||||||
|
|
||||||
|
This group is not yet implemented.
|
||||||
""")
|
""")
|
||||||
|
|
||||||
expand = XFormGroup('expand', """
|
expand = XFormGroup('expand', """
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ opt_level = EnumSetting(
|
|||||||
|
|
||||||
enable_verifier = BoolSetting(
|
enable_verifier = BoolSetting(
|
||||||
"""
|
"""
|
||||||
Run the Cretonne IL verifier at strategic times during compilation.
|
Run the Cretonne IR verifier at strategic times during compilation.
|
||||||
|
|
||||||
This makes compilation slower but catches many bugs. The verifier is
|
This makes compilation slower but catches many bugs. The verifier is
|
||||||
disabled by default, except when reading Cretonne IL from a text file.
|
disabled by default, except when reading Cretonne IR from a text file.
|
||||||
""",
|
""",
|
||||||
default=True)
|
default=True)
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,11 @@ import gen_legalizer
|
|||||||
import gen_registers
|
import gen_registers
|
||||||
import gen_binemit
|
import gen_binemit
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(description='Generate sources for Cretonne.')
|
|
||||||
|
def main():
|
||||||
|
# type: () -> None
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description='Generate sources for Cretonne.')
|
||||||
parser.add_argument('--out-dir', help='set output directory')
|
parser.add_argument('--out-dir', help='set output directory')
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
@@ -30,3 +34,7 @@ gen_legalizer.generate(isas, out_dir)
|
|||||||
gen_registers.generate(isas, out_dir)
|
gen_registers.generate(isas, out_dir)
|
||||||
gen_binemit.generate(isas, out_dir)
|
gen_binemit.generate(isas, out_dir)
|
||||||
gen_build_deps.generate()
|
gen_build_deps.generate()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|||||||
@@ -559,7 +559,7 @@ class Enumerator(Literal):
|
|||||||
is an AST leaf node representing one of the values.
|
is an AST leaf node representing one of the values.
|
||||||
|
|
||||||
:param kind: The enumerated `ImmediateKind` containing the value.
|
:param kind: The enumerated `ImmediateKind` containing the value.
|
||||||
:param value: The textual IL representation of the value.
|
:param value: The textual IR representation of the value.
|
||||||
|
|
||||||
`Enumerator` nodes are not usually created directly. They are created by
|
`Enumerator` nodes are not usually created directly. They are created by
|
||||||
using the dot syntax on immediate kinds: `intcc.ult`.
|
using the dot syntax on immediate kinds: `intcc.ult`.
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ from .instructions import InstructionGroup
|
|||||||
try:
|
try:
|
||||||
from typing import Tuple, Union, Any, Iterable, Sequence, List, Set, Dict, TYPE_CHECKING # noqa
|
from typing import Tuple, Union, Any, Iterable, Sequence, List, Set, Dict, TYPE_CHECKING # noqa
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .instructions import MaybeBoundInst, InstructionGroup, InstructionFormat # noqa
|
from .instructions import MaybeBoundInst, InstructionFormat # noqa
|
||||||
from .predicates import PredNode, PredKey # noqa
|
from .predicates import PredNode, PredKey # noqa
|
||||||
from .settings import SettingGroup # noqa
|
from .settings import SettingGroup # noqa
|
||||||
from .registers import RegBank # noqa
|
from .registers import RegBank # noqa
|
||||||
@@ -172,8 +172,7 @@ class TargetISA(object):
|
|||||||
"""
|
"""
|
||||||
for cpumode in self.cpumodes:
|
for cpumode in self.cpumodes:
|
||||||
self.legalize_code(cpumode.default_legalize)
|
self.legalize_code(cpumode.default_legalize)
|
||||||
for x in sorted(cpumode.type_legalize.values(),
|
for x in cpumode.type_legalize.values():
|
||||||
key=lambda x: x.name):
|
|
||||||
self.legalize_code(x)
|
self.legalize_code(x)
|
||||||
|
|
||||||
def legalize_code(self, xgrp):
|
def legalize_code(self, xgrp):
|
||||||
@@ -232,7 +231,7 @@ class CPUMode(object):
|
|||||||
# Tables for configuring legalization actions when no valid encoding
|
# Tables for configuring legalization actions when no valid encoding
|
||||||
# exists for an instruction.
|
# exists for an instruction.
|
||||||
self.default_legalize = None # type: XFormGroup
|
self.default_legalize = None # type: XFormGroup
|
||||||
self.type_legalize = dict() # type: Dict[ValueType, XFormGroup]
|
self.type_legalize = OrderedDict() # type: OrderedDict[ValueType, XFormGroup] # noqa
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
# type: () -> str
|
# type: () -> str
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
cd $(dirname "$0")
|
cd $(dirname "$0")
|
||||||
|
|
||||||
runif() {
|
function runif() {
|
||||||
if command -v "$1" > /dev/null; then
|
if command -v "$1" > /dev/null; then
|
||||||
echo " === $1 ==="
|
echo " === $1 ==="
|
||||||
"$@"
|
"$@"
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ def gen_isa(isa, fmt):
|
|||||||
fmt.line('let bits = encoding.bits();')
|
fmt.line('let bits = encoding.bits();')
|
||||||
with fmt.indented('match func.encodings[inst].recipe() {', '}'):
|
with fmt.indented('match func.encodings[inst].recipe() {', '}'):
|
||||||
for i, recipe in enumerate(isa.all_recipes):
|
for i, recipe in enumerate(isa.all_recipes):
|
||||||
fmt.comment(recipe.name)
|
fmt.comment('Recipe {}'.format(recipe.name))
|
||||||
with fmt.indented('{} => {{'.format(i), '}'):
|
with fmt.indented('{} => {{'.format(i), '}'):
|
||||||
gen_recipe(recipe, fmt)
|
gen_recipe(recipe, fmt)
|
||||||
fmt.line('_ => {},')
|
fmt.line('_ => {},')
|
||||||
|
|||||||
@@ -600,8 +600,8 @@ def make_tables(cpumode):
|
|||||||
table[ty][inst].encodings.append(enc)
|
table[ty][inst].encodings.append(enc)
|
||||||
|
|
||||||
# Ensure there are level 1 table entries for all types with a custom
|
# Ensure there are level 1 table entries for all types with a custom
|
||||||
# legalize action. Try to be stable relative to dict ordering.
|
# legalize action.
|
||||||
for ty in sorted(cpumode.type_legalize.keys(), key=str):
|
for ty in cpumode.type_legalize.keys():
|
||||||
table[ty]
|
table[ty]
|
||||||
|
|
||||||
return table
|
return table
|
||||||
@@ -756,7 +756,7 @@ def emit_recipe_constraints(isa, fmt):
|
|||||||
'static RECIPE_CONSTRAINTS: [RecipeConstraints; {}] = ['
|
'static RECIPE_CONSTRAINTS: [RecipeConstraints; {}] = ['
|
||||||
.format(len(isa.all_recipes)), '];'):
|
.format(len(isa.all_recipes)), '];'):
|
||||||
for r in isa.all_recipes:
|
for r in isa.all_recipes:
|
||||||
fmt.comment(r.name)
|
fmt.comment('Constraints for recipe {}:'.format(r.name))
|
||||||
tied_i2o, tied_o2i = r.ties()
|
tied_i2o, tied_o2i = r.ties()
|
||||||
fixed_ins, fixed_outs = r.fixed_ops()
|
fixed_ins, fixed_outs = r.fixed_ops()
|
||||||
with fmt.indented('RecipeConstraints {', '},'):
|
with fmt.indented('RecipeConstraints {', '},'):
|
||||||
@@ -830,7 +830,7 @@ def emit_recipe_sizing(isa, fmt):
|
|||||||
'static RECIPE_SIZING: [RecipeSizing; {}] = ['
|
'static RECIPE_SIZING: [RecipeSizing; {}] = ['
|
||||||
.format(len(isa.all_recipes)), '];'):
|
.format(len(isa.all_recipes)), '];'):
|
||||||
for r in isa.all_recipes:
|
for r in isa.all_recipes:
|
||||||
fmt.comment(r.name)
|
fmt.comment('Code size information for recipe {}:'.format(r.name))
|
||||||
with fmt.indented('RecipeSizing {', '},'):
|
with fmt.indented('RecipeSizing {', '},'):
|
||||||
fmt.format('bytes: {},', r.size)
|
fmt.format('bytes: {},', r.size)
|
||||||
if r.branch_range:
|
if r.branch_range:
|
||||||
|
|||||||
@@ -49,11 +49,11 @@ def gen_formats(fmt):
|
|||||||
with fmt.indented(
|
with fmt.indented(
|
||||||
"fn from(inst: &'a InstructionData) -> InstructionFormat {",
|
"fn from(inst: &'a InstructionData) -> InstructionFormat {",
|
||||||
'}'):
|
'}'):
|
||||||
with fmt.indented('match *inst {', '}'):
|
m = srcgen.Match('*inst')
|
||||||
for f in InstructionFormat.all_formats:
|
for f in InstructionFormat.all_formats:
|
||||||
fmt.line(('InstructionData::{} {{ .. }} => ' +
|
m.arm('InstructionData::' + f.name, ['..'],
|
||||||
'InstructionFormat::{},')
|
'InstructionFormat::' + f.name)
|
||||||
.format(f.name, f.name))
|
fmt.match(m)
|
||||||
fmt.line()
|
fmt.line()
|
||||||
|
|
||||||
|
|
||||||
@@ -74,7 +74,7 @@ def gen_arguments_method(fmt, is_mut):
|
|||||||
'pool: &\'a {m}ir::ValueListPool) -> '
|
'pool: &\'a {m}ir::ValueListPool) -> '
|
||||||
'&{m}[Value] {{'
|
'&{m}[Value] {{'
|
||||||
.format(f=method, m=mut), '}'):
|
.format(f=method, m=mut), '}'):
|
||||||
with fmt.indented('match *self {', '}'):
|
m = srcgen.Match('*self')
|
||||||
for f in InstructionFormat.all_formats:
|
for f in InstructionFormat.all_formats:
|
||||||
n = 'InstructionData::' + f.name
|
n = 'InstructionData::' + f.name
|
||||||
|
|
||||||
@@ -82,25 +82,56 @@ def gen_arguments_method(fmt, is_mut):
|
|||||||
# list. We don't split them up, just return it all as variable
|
# list. We don't split them up, just return it all as variable
|
||||||
# arguments. (I expect the distinction to go away).
|
# arguments. (I expect the distinction to go away).
|
||||||
if f.has_value_list:
|
if f.has_value_list:
|
||||||
arg = ''.format(mut)
|
m.arm(n, ['ref {}args'.format(mut), '..'],
|
||||||
fmt.line(
|
'args.{}(pool)'.format(as_slice))
|
||||||
'{} {{ ref {}args, .. }} => args.{}(pool),'
|
|
||||||
.format(n, mut, as_slice))
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Fixed args.
|
# Fixed args.
|
||||||
|
fields = []
|
||||||
if f.num_value_operands == 0:
|
if f.num_value_operands == 0:
|
||||||
arg = '&{}[]'.format(mut)
|
arg = '&{}[]'.format(mut)
|
||||||
capture = ''
|
|
||||||
elif f.num_value_operands == 1:
|
elif f.num_value_operands == 1:
|
||||||
capture = 'ref {}arg, '.format(mut)
|
fields.append('ref {}arg'.format(mut))
|
||||||
arg = '{}(arg)'.format(rslice)
|
arg = '{}(arg)'.format(rslice)
|
||||||
else:
|
else:
|
||||||
capture = 'ref {}args, '.format(mut)
|
args = 'args_arity{}'.format(f.num_value_operands)
|
||||||
arg = 'args'
|
fields.append('args: ref {}{}'.format(mut, args))
|
||||||
|
arg = args
|
||||||
|
fields.append('..')
|
||||||
|
m.arm(n, fields, arg)
|
||||||
|
fmt.match(m)
|
||||||
|
|
||||||
|
|
||||||
|
def gen_instruction_data(fmt):
|
||||||
|
# type: (srcgen.Formatter) -> None
|
||||||
|
"""
|
||||||
|
Generate the InstructionData enum.
|
||||||
|
|
||||||
|
Every variant must contain `opcode` and `ty` fields. An instruction that
|
||||||
|
doesn't produce a value should have its `ty` field set to `VOID`. The size
|
||||||
|
of `InstructionData` should be kept at 16 bytes on 64-bit architectures. If
|
||||||
|
more space is needed to represent an instruction, use a `Box<AuxData>` to
|
||||||
|
store the additional information out of line.
|
||||||
|
"""
|
||||||
|
|
||||||
|
fmt.line('#[derive(Clone, Debug, Hash, PartialEq, Eq)]')
|
||||||
|
fmt.line('#[allow(missing_docs)]')
|
||||||
|
with fmt.indented('pub enum InstructionData {', '}'):
|
||||||
|
for f in InstructionFormat.all_formats:
|
||||||
|
with fmt.indented('{} {{'.format(f.name), '},'):
|
||||||
|
fmt.line('opcode: Opcode,')
|
||||||
|
if f.typevar_operand is None:
|
||||||
|
pass
|
||||||
|
elif f.has_value_list:
|
||||||
|
fmt.line('args: ValueList,')
|
||||||
|
elif f.num_value_operands == 1:
|
||||||
|
fmt.line('arg: Value,')
|
||||||
|
else:
|
||||||
|
fmt.line('args: [Value; {}],'.format(f.num_value_operands))
|
||||||
|
for field in f.imm_fields:
|
||||||
fmt.line(
|
fmt.line(
|
||||||
'{} {{ {}.. }} => {},'
|
'{}: {},'
|
||||||
.format(n, capture, arg))
|
.format(field.member, field.kind.rust_type))
|
||||||
|
|
||||||
|
|
||||||
def gen_instruction_data_impl(fmt):
|
def gen_instruction_data_impl(fmt):
|
||||||
@@ -123,39 +154,37 @@ def gen_instruction_data_impl(fmt):
|
|||||||
with fmt.indented('impl InstructionData {', '}'):
|
with fmt.indented('impl InstructionData {', '}'):
|
||||||
fmt.doc_comment('Get the opcode of this instruction.')
|
fmt.doc_comment('Get the opcode of this instruction.')
|
||||||
with fmt.indented('pub fn opcode(&self) -> Opcode {', '}'):
|
with fmt.indented('pub fn opcode(&self) -> Opcode {', '}'):
|
||||||
with fmt.indented('match *self {', '}'):
|
m = srcgen.Match('*self')
|
||||||
for f in InstructionFormat.all_formats:
|
for f in InstructionFormat.all_formats:
|
||||||
fmt.line(
|
m.arm('InstructionData::' + f.name, ['opcode', '..'],
|
||||||
'InstructionData::{} {{ opcode, .. }} => opcode,'
|
'opcode')
|
||||||
.format(f.name))
|
fmt.match(m)
|
||||||
fmt.line()
|
fmt.line()
|
||||||
|
|
||||||
fmt.doc_comment('Get the controlling type variable operand.')
|
fmt.doc_comment('Get the controlling type variable operand.')
|
||||||
with fmt.indented(
|
with fmt.indented(
|
||||||
'pub fn typevar_operand(&self, pool: &ir::ValueListPool) -> '
|
'pub fn typevar_operand(&self, pool: &ir::ValueListPool) -> '
|
||||||
'Option<Value> {', '}'):
|
'Option<Value> {', '}'):
|
||||||
with fmt.indented('match *self {', '}'):
|
m = srcgen.Match('*self')
|
||||||
for f in InstructionFormat.all_formats:
|
for f in InstructionFormat.all_formats:
|
||||||
n = 'InstructionData::' + f.name
|
n = 'InstructionData::' + f.name
|
||||||
if f.typevar_operand is None:
|
if f.typevar_operand is None:
|
||||||
fmt.line(n + ' { .. } => None,')
|
m.arm(n, ['..'], 'None')
|
||||||
elif f.has_value_list:
|
elif f.has_value_list:
|
||||||
# We keep all arguments in a value list.
|
# We keep all arguments in a value list.
|
||||||
i = f.typevar_operand
|
i = f.typevar_operand
|
||||||
fmt.line(
|
m.arm(n, ['ref args', '..'],
|
||||||
'{} {{ ref args, .. }} => '
|
'args.get({}, pool)'.format(i))
|
||||||
'args.get({}, pool),'.format(n, i))
|
|
||||||
elif f.num_value_operands == 1:
|
elif f.num_value_operands == 1:
|
||||||
# We have a single value operand called 'arg'.
|
# We have a single value operand called 'arg'.
|
||||||
fmt.line(n + ' { arg, .. } => Some(arg),')
|
m.arm(n, ['arg', '..'], 'Some(arg)')
|
||||||
else:
|
else:
|
||||||
# We have multiple value operands and an array `args`.
|
# We have multiple value operands and an array `args`.
|
||||||
# Which `args` index to use?
|
# Which `args` index to use?
|
||||||
i = f.typevar_operand
|
args = 'args_arity{}'.format(f.num_value_operands)
|
||||||
fmt.line(
|
m.arm(n, ['args: ref {}'.format(args), '..'],
|
||||||
n +
|
'Some({}[{}])'.format(args, f.typevar_operand))
|
||||||
' {{ ref args, .. }} => Some(args[{}]),'
|
fmt.match(m)
|
||||||
.format(i))
|
|
||||||
fmt.line()
|
fmt.line()
|
||||||
|
|
||||||
fmt.doc_comment(
|
fmt.doc_comment(
|
||||||
@@ -184,13 +213,13 @@ def gen_instruction_data_impl(fmt):
|
|||||||
with fmt.indented(
|
with fmt.indented(
|
||||||
'pub fn take_value_list(&mut self) -> Option<ir::ValueList> {',
|
'pub fn take_value_list(&mut self) -> Option<ir::ValueList> {',
|
||||||
'}'):
|
'}'):
|
||||||
with fmt.indented('match *self {', '}'):
|
m = srcgen.Match('*self')
|
||||||
for f in InstructionFormat.all_formats:
|
for f in InstructionFormat.all_formats:
|
||||||
n = 'InstructionData::' + f.name
|
n = 'InstructionData::' + f.name
|
||||||
if f.has_value_list:
|
if f.has_value_list:
|
||||||
fmt.line(
|
m.arm(n, ['ref mut args', '..'], 'Some(args.take())')
|
||||||
n + ' { ref mut args, .. } => Some(args.take()),')
|
m.arm('_', [], 'None')
|
||||||
fmt.line('_ => None,')
|
fmt.match(m)
|
||||||
fmt.line()
|
fmt.line()
|
||||||
|
|
||||||
fmt.doc_comment(
|
fmt.doc_comment(
|
||||||
@@ -275,14 +304,12 @@ def gen_opcodes(groups, fmt):
|
|||||||
fmt.doc_comment(Instruction.ATTRIBS[attr])
|
fmt.doc_comment(Instruction.ATTRIBS[attr])
|
||||||
with fmt.indented('pub fn {}(self) -> bool {{'
|
with fmt.indented('pub fn {}(self) -> bool {{'
|
||||||
.format(attr), '}'):
|
.format(attr), '}'):
|
||||||
with fmt.indented('match self {', '}'):
|
m = srcgen.Match('self')
|
||||||
for i in instrs:
|
for i in instrs:
|
||||||
if getattr(i, attr):
|
if getattr(i, attr):
|
||||||
fmt.format(
|
m.arm('Opcode::' + i.camel_name, [], 'true')
|
||||||
'Opcode::{} => true,',
|
m.arm('_', [], 'false')
|
||||||
i.camel_name, i.name)
|
fmt.match(m)
|
||||||
|
|
||||||
fmt.line('_ => false,')
|
|
||||||
fmt.line()
|
fmt.line()
|
||||||
fmt.line()
|
fmt.line()
|
||||||
|
|
||||||
@@ -299,9 +326,10 @@ def gen_opcodes(groups, fmt):
|
|||||||
|
|
||||||
# Generate a private opcode_name function.
|
# Generate a private opcode_name function.
|
||||||
with fmt.indented('fn opcode_name(opc: Opcode) -> &\'static str {', '}'):
|
with fmt.indented('fn opcode_name(opc: Opcode) -> &\'static str {', '}'):
|
||||||
with fmt.indented('match opc {', '}'):
|
m = srcgen.Match('opc')
|
||||||
for i in instrs:
|
for i in instrs:
|
||||||
fmt.format('Opcode::{} => "{}",', i.camel_name, i.name)
|
m.arm('Opcode::' + i.camel_name, [], '"{}"'.format(i.name))
|
||||||
|
fmt.match(m)
|
||||||
fmt.line()
|
fmt.line()
|
||||||
|
|
||||||
# Generate an opcode hash table for looking up opcodes by name.
|
# Generate an opcode hash table for looking up opcodes by name.
|
||||||
@@ -655,7 +683,7 @@ def gen_builder(insts, fmt):
|
|||||||
fmt.doc_comment("""
|
fmt.doc_comment("""
|
||||||
Convenience methods for building instructions.
|
Convenience methods for building instructions.
|
||||||
|
|
||||||
The `InstrBuilder` trait has one method per instruction opcode for
|
The `InstBuilder` trait has one method per instruction opcode for
|
||||||
conveniently constructing the instruction with minimum arguments.
|
conveniently constructing the instruction with minimum arguments.
|
||||||
Polymorphic instructions infer their result types from the input
|
Polymorphic instructions infer their result types from the input
|
||||||
arguments when possible. In some cases, an explicit `ctrl_typevar`
|
arguments when possible. In some cases, an explicit `ctrl_typevar`
|
||||||
@@ -682,13 +710,15 @@ def generate(isas, out_dir):
|
|||||||
# opcodes.rs
|
# opcodes.rs
|
||||||
fmt = srcgen.Formatter()
|
fmt = srcgen.Formatter()
|
||||||
gen_formats(fmt)
|
gen_formats(fmt)
|
||||||
|
gen_instruction_data(fmt)
|
||||||
|
fmt.line()
|
||||||
gen_instruction_data_impl(fmt)
|
gen_instruction_data_impl(fmt)
|
||||||
fmt.line()
|
fmt.line()
|
||||||
instrs = gen_opcodes(groups, fmt)
|
instrs = gen_opcodes(groups, fmt)
|
||||||
gen_type_constraints(fmt, instrs)
|
gen_type_constraints(fmt, instrs)
|
||||||
fmt.update_file('opcodes.rs', out_dir)
|
fmt.update_file('opcodes.rs', out_dir)
|
||||||
|
|
||||||
# builder.rs
|
# inst_builder.rs
|
||||||
fmt = srcgen.Formatter()
|
fmt = srcgen.Formatter()
|
||||||
gen_builder(instrs, fmt)
|
gen_builder(instrs, fmt)
|
||||||
fmt.update_file('builder.rs', out_dir)
|
fmt.update_file('inst_builder.rs', out_dir)
|
||||||
|
|||||||
@@ -103,18 +103,19 @@ def emit_runtime_typecheck(check, fmt, type_sets):
|
|||||||
|
|
||||||
base_exp = build_derived_expr(tv.base)
|
base_exp = build_derived_expr(tv.base)
|
||||||
if (tv.derived_func == TypeVar.LANEOF):
|
if (tv.derived_func == TypeVar.LANEOF):
|
||||||
return "{}.map(|t: Type| -> t.lane_type())".format(base_exp)
|
return "{}.map(|t: ir::Type| t.lane_type())".format(base_exp)
|
||||||
elif (tv.derived_func == TypeVar.ASBOOL):
|
elif (tv.derived_func == TypeVar.ASBOOL):
|
||||||
return "{}.map(|t: Type| -> t.as_bool())".format(base_exp)
|
return "{}.map(|t: ir::Type| t.as_bool())".format(base_exp)
|
||||||
elif (tv.derived_func == TypeVar.HALFWIDTH):
|
elif (tv.derived_func == TypeVar.HALFWIDTH):
|
||||||
return "{}.and_then(|t: Type| -> t.half_width())".format(base_exp)
|
return "{}.and_then(|t: ir::Type| t.half_width())".format(base_exp)
|
||||||
elif (tv.derived_func == TypeVar.DOUBLEWIDTH):
|
elif (tv.derived_func == TypeVar.DOUBLEWIDTH):
|
||||||
return "{}.and_then(|t: Type| -> t.double_width())"\
|
return "{}.and_then(|t: ir::Type| t.double_width())"\
|
||||||
.format(base_exp)
|
.format(base_exp)
|
||||||
elif (tv.derived_func == TypeVar.HALFVECTOR):
|
elif (tv.derived_func == TypeVar.HALFVECTOR):
|
||||||
return "{}.and_then(|t: Type| -> t.half_vector())".format(base_exp)
|
return "{}.and_then(|t: ir::Type| t.half_vector())"\
|
||||||
|
.format(base_exp)
|
||||||
elif (tv.derived_func == TypeVar.DOUBLEVECTOR):
|
elif (tv.derived_func == TypeVar.DOUBLEVECTOR):
|
||||||
return "{}.and_then(|t: Type| -> t.by(2))".format(base_exp)
|
return "{}.and_then(|t: ir::Type| t.by(2))".format(base_exp)
|
||||||
else:
|
else:
|
||||||
assert False, "Unknown derived function {}".format(tv.derived_func)
|
assert False, "Unknown derived function {}".format(tv.derived_func)
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ def gen_enum_types(sgrp, fmt):
|
|||||||
if not isinstance(setting, EnumSetting):
|
if not isinstance(setting, EnumSetting):
|
||||||
continue
|
continue
|
||||||
ty = camel_case(setting.name)
|
ty = camel_case(setting.name)
|
||||||
fmt.doc_comment('Values for {}.'.format(setting))
|
fmt.doc_comment('Values for `{}`.'.format(setting))
|
||||||
fmt.line('#[derive(Debug, PartialEq, Eq)]')
|
fmt.line('#[derive(Debug, PartialEq, Eq)]')
|
||||||
with fmt.indented('pub enum {} {{'.format(ty), '}'):
|
with fmt.indented('pub enum {} {{'.format(ty), '}'):
|
||||||
for v in setting.values:
|
for v in setting.values:
|
||||||
@@ -57,12 +57,11 @@ def gen_getter(setting, sgrp, fmt):
|
|||||||
ty = camel_case(setting.name)
|
ty = camel_case(setting.name)
|
||||||
proto = 'pub fn {}(&self) -> {}'.format(setting.name, ty)
|
proto = 'pub fn {}(&self) -> {}'.format(setting.name, ty)
|
||||||
with fmt.indented(proto + ' {', '}'):
|
with fmt.indented(proto + ' {', '}'):
|
||||||
with fmt.indented(
|
m = srcgen.Match('self.bytes[{}]'.format(setting.byte_offset))
|
||||||
'match self.bytes[{}] {{'
|
|
||||||
.format(setting.byte_offset), '}'):
|
|
||||||
for i, v in enumerate(setting.values):
|
for i, v in enumerate(setting.values):
|
||||||
fmt.line('{} => {}::{},'.format(i, ty, camel_case(v)))
|
m.arm(str(i), [], '{}::{}'.format(ty, camel_case(v)))
|
||||||
fmt.line('_ => panic!("Invalid enum value"),')
|
m.arm('_', [], 'panic!("Invalid enum value")')
|
||||||
|
fmt.match(m)
|
||||||
else:
|
else:
|
||||||
raise AssertionError("Unknown setting kind")
|
raise AssertionError("Unknown setting kind")
|
||||||
|
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ from base.immediates import floatcc
|
|||||||
ISA = TargetISA('intel', [base.instructions.GROUP, x86.GROUP])
|
ISA = TargetISA('intel', [base.instructions.GROUP, x86.GROUP])
|
||||||
|
|
||||||
# CPU modes for 32-bit and 64-bit operation.
|
# CPU modes for 32-bit and 64-bit operation.
|
||||||
I64 = CPUMode('I64', ISA)
|
X86_64 = CPUMode('I64', ISA)
|
||||||
I32 = CPUMode('I32', ISA)
|
X86_32 = CPUMode('I32', ISA)
|
||||||
|
|
||||||
# The set of floating point condition codes that are directly supported.
|
# The set of floating point condition codes that are directly supported.
|
||||||
# Other condition codes need to be reversed or expressed as two tests.
|
# Other condition codes need to be reversed or expressed as two tests.
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from __future__ import absolute_import
|
|||||||
from cdsl.predicates import IsUnsignedInt, Not, And
|
from cdsl.predicates import IsUnsignedInt, Not, And
|
||||||
from base import instructions as base
|
from base import instructions as base
|
||||||
from base.formats import UnaryImm
|
from base.formats import UnaryImm
|
||||||
from .defs import I32, I64
|
from .defs import X86_64, X86_32
|
||||||
from . import recipes as r
|
from . import recipes as r
|
||||||
from . import settings as cfg
|
from . import settings as cfg
|
||||||
from . import instructions as x86
|
from . import instructions as x86
|
||||||
@@ -22,16 +22,16 @@ except ImportError:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
I32.legalize_monomorphic(expand_flags)
|
X86_32.legalize_monomorphic(expand_flags)
|
||||||
I32.legalize_type(
|
X86_32.legalize_type(
|
||||||
default=narrow,
|
default=narrow,
|
||||||
b1=expand_flags,
|
b1=expand_flags,
|
||||||
i32=intel_expand,
|
i32=intel_expand,
|
||||||
f32=intel_expand,
|
f32=intel_expand,
|
||||||
f64=intel_expand)
|
f64=intel_expand)
|
||||||
|
|
||||||
I64.legalize_monomorphic(expand_flags)
|
X86_64.legalize_monomorphic(expand_flags)
|
||||||
I64.legalize_type(
|
X86_64.legalize_type(
|
||||||
default=narrow,
|
default=narrow,
|
||||||
b1=expand_flags,
|
b1=expand_flags,
|
||||||
i32=intel_expand,
|
i32=intel_expand,
|
||||||
@@ -44,61 +44,61 @@ I64.legalize_type(
|
|||||||
# Helper functions for generating encodings.
|
# Helper functions for generating encodings.
|
||||||
#
|
#
|
||||||
|
|
||||||
def enc_i64(inst, recipe, *args, **kwargs):
|
def enc_x86_64(inst, recipe, *args, **kwargs):
|
||||||
# type: (MaybeBoundInst, r.TailRecipe, *int, **int) -> None
|
# type: (MaybeBoundInst, r.TailRecipe, *int, **int) -> None
|
||||||
"""
|
"""
|
||||||
Add encodings for `inst` to I64 with and without a REX prefix.
|
Add encodings for `inst` to X86_64 with and without a REX prefix.
|
||||||
"""
|
"""
|
||||||
I64.enc(inst, *recipe.rex(*args, **kwargs))
|
X86_64.enc(inst, *recipe.rex(*args, **kwargs))
|
||||||
I64.enc(inst, *recipe(*args, **kwargs))
|
X86_64.enc(inst, *recipe(*args, **kwargs))
|
||||||
|
|
||||||
|
|
||||||
def enc_both(inst, recipe, *args, **kwargs):
|
def enc_both(inst, recipe, *args, **kwargs):
|
||||||
# type: (MaybeBoundInst, r.TailRecipe, *int, **Any) -> None
|
# type: (MaybeBoundInst, r.TailRecipe, *int, **Any) -> None
|
||||||
"""
|
"""
|
||||||
Add encodings for `inst` to both I32 and I64.
|
Add encodings for `inst` to both X86_32 and X86_64.
|
||||||
"""
|
"""
|
||||||
I32.enc(inst, *recipe(*args, **kwargs))
|
X86_32.enc(inst, *recipe(*args, **kwargs))
|
||||||
enc_i64(inst, recipe, *args, **kwargs)
|
enc_x86_64(inst, recipe, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def enc_i32_i64(inst, recipe, *args, **kwargs):
|
def enc_i32_i64(inst, recipe, *args, **kwargs):
|
||||||
# type: (MaybeBoundInst, r.TailRecipe, *int, **int) -> None
|
# type: (MaybeBoundInst, r.TailRecipe, *int, **int) -> None
|
||||||
"""
|
"""
|
||||||
Add encodings for `inst.i32` to I32.
|
Add encodings for `inst.i32` to X86_32.
|
||||||
Add encodings for `inst.i32` to I64 with and without REX.
|
Add encodings for `inst.i32` to X86_64 with and without REX.
|
||||||
Add encodings for `inst.i64` to I64 with a REX.W prefix.
|
Add encodings for `inst.i64` to X86_64 with a REX.W prefix.
|
||||||
"""
|
"""
|
||||||
I32.enc(inst.i32, *recipe(*args, **kwargs))
|
X86_32.enc(inst.i32, *recipe(*args, **kwargs))
|
||||||
|
|
||||||
# REX-less encoding must come after REX encoding so we don't use it by
|
# REX-less encoding must come after REX encoding so we don't use it by
|
||||||
# default. Otherwise reg-alloc would never use r8 and up.
|
# default. Otherwise reg-alloc would never use r8 and up.
|
||||||
I64.enc(inst.i32, *recipe.rex(*args, **kwargs))
|
X86_64.enc(inst.i32, *recipe.rex(*args, **kwargs))
|
||||||
I64.enc(inst.i32, *recipe(*args, **kwargs))
|
X86_64.enc(inst.i32, *recipe(*args, **kwargs))
|
||||||
|
|
||||||
I64.enc(inst.i64, *recipe.rex(*args, w=1, **kwargs))
|
X86_64.enc(inst.i64, *recipe.rex(*args, w=1, **kwargs))
|
||||||
|
|
||||||
|
|
||||||
def enc_i32_i64_ld_st(inst, w_bit, recipe, *args, **kwargs):
|
def enc_i32_i64_ld_st(inst, w_bit, recipe, *args, **kwargs):
|
||||||
# type: (MaybeBoundInst, bool, r.TailRecipe, *int, **int) -> None
|
# type: (MaybeBoundInst, bool, r.TailRecipe, *int, **int) -> None
|
||||||
"""
|
"""
|
||||||
Add encodings for `inst.i32` to I32.
|
Add encodings for `inst.i32` to X86_32.
|
||||||
Add encodings for `inst.i32` to I64 with and without REX.
|
Add encodings for `inst.i32` to X86_64 with and without REX.
|
||||||
Add encodings for `inst.i64` to I64 with a REX prefix, using the `w_bit`
|
Add encodings for `inst.i64` to X86_64 with a REX prefix, using the `w_bit`
|
||||||
argument to determine whether or not to set the REX.W bit.
|
argument to determine whether or not to set the REX.W bit.
|
||||||
"""
|
"""
|
||||||
I32.enc(inst.i32.any, *recipe(*args, **kwargs))
|
X86_32.enc(inst.i32.any, *recipe(*args, **kwargs))
|
||||||
|
|
||||||
# REX-less encoding must come after REX encoding so we don't use it by
|
# REX-less encoding must come after REX encoding so we don't use it by
|
||||||
# default. Otherwise reg-alloc would never use r8 and up.
|
# default. Otherwise reg-alloc would never use r8 and up.
|
||||||
I64.enc(inst.i32.any, *recipe.rex(*args, **kwargs))
|
X86_64.enc(inst.i32.any, *recipe.rex(*args, **kwargs))
|
||||||
I64.enc(inst.i32.any, *recipe(*args, **kwargs))
|
X86_64.enc(inst.i32.any, *recipe(*args, **kwargs))
|
||||||
|
|
||||||
if w_bit:
|
if w_bit:
|
||||||
I64.enc(inst.i64.any, *recipe.rex(*args, w=1, **kwargs))
|
X86_64.enc(inst.i64.any, *recipe.rex(*args, w=1, **kwargs))
|
||||||
else:
|
else:
|
||||||
I64.enc(inst.i64.any, *recipe.rex(*args, **kwargs))
|
X86_64.enc(inst.i64.any, *recipe.rex(*args, **kwargs))
|
||||||
I64.enc(inst.i64.any, *recipe(*args, **kwargs))
|
X86_64.enc(inst.i64.any, *recipe(*args, **kwargs))
|
||||||
|
|
||||||
|
|
||||||
for inst, opc in [
|
for inst, opc in [
|
||||||
@@ -141,19 +141,22 @@ for inst, rrr in [
|
|||||||
# band_imm.i32. Can even use the single-byte immediate for 0xffff_ffXX masks.
|
# band_imm.i32. Can even use the single-byte immediate for 0xffff_ffXX masks.
|
||||||
|
|
||||||
# Immediate constants.
|
# Immediate constants.
|
||||||
I32.enc(base.iconst.i32, *r.puid(0xb8))
|
X86_32.enc(base.iconst.i32, *r.puid(0xb8))
|
||||||
|
|
||||||
I64.enc(base.iconst.i32, *r.puid.rex(0xb8))
|
X86_64.enc(base.iconst.i32, *r.puid.rex(0xb8))
|
||||||
I64.enc(base.iconst.i32, *r.puid(0xb8))
|
X86_64.enc(base.iconst.i32, *r.puid(0xb8))
|
||||||
# The 32-bit immediate movl also zero-extends to 64 bits.
|
# The 32-bit immediate movl also zero-extends to 64 bits.
|
||||||
I64.enc(base.iconst.i64, *r.puid.rex(0xb8),
|
X86_64.enc(base.iconst.i64, *r.puid.rex(0xb8),
|
||||||
instp=IsUnsignedInt(UnaryImm.imm, 32))
|
instp=IsUnsignedInt(UnaryImm.imm, 32))
|
||||||
I64.enc(base.iconst.i64, *r.puid(0xb8),
|
X86_64.enc(base.iconst.i64, *r.puid(0xb8),
|
||||||
instp=IsUnsignedInt(UnaryImm.imm, 32))
|
instp=IsUnsignedInt(UnaryImm.imm, 32))
|
||||||
# Sign-extended 32-bit immediate.
|
# Sign-extended 32-bit immediate.
|
||||||
I64.enc(base.iconst.i64, *r.uid.rex(0xc7, rrr=0, w=1))
|
X86_64.enc(base.iconst.i64, *r.uid.rex(0xc7, rrr=0, w=1))
|
||||||
# Finally, the 0xb8 opcode takes an 8-byte immediate with a REX.W prefix.
|
# Finally, the 0xb8 opcode takes an 8-byte immediate with a REX.W prefix.
|
||||||
I64.enc(base.iconst.i64, *r.puiq.rex(0xb8, w=1))
|
X86_64.enc(base.iconst.i64, *r.puiq.rex(0xb8, w=1))
|
||||||
|
|
||||||
|
# bool constants.
|
||||||
|
enc_both(base.bconst.b1, r.puid_bool, 0xb8)
|
||||||
|
|
||||||
# Shifts and rotates.
|
# Shifts and rotates.
|
||||||
# Note that the dynamic shift amount is only masked by 5 or 6 bits; the 8-bit
|
# Note that the dynamic shift amount is only masked by 5 or 6 bits; the 8-bit
|
||||||
@@ -164,38 +167,46 @@ for inst, rrr in [
|
|||||||
(base.ishl, 4),
|
(base.ishl, 4),
|
||||||
(base.ushr, 5),
|
(base.ushr, 5),
|
||||||
(base.sshr, 7)]:
|
(base.sshr, 7)]:
|
||||||
I32.enc(inst.i32.any, *r.rc(0xd3, rrr=rrr))
|
# Cannot use enc_i32_i64 for this pattern because instructions require
|
||||||
I64.enc(inst.i64.any, *r.rc.rex(0xd3, rrr=rrr, w=1))
|
# .any suffix.
|
||||||
I64.enc(inst.i32.any, *r.rc.rex(0xd3, rrr=rrr))
|
X86_32.enc(inst.i32.any, *r.rc(0xd3, rrr=rrr))
|
||||||
I64.enc(inst.i32.any, *r.rc(0xd3, rrr=rrr))
|
X86_64.enc(inst.i64.any, *r.rc.rex(0xd3, rrr=rrr, w=1))
|
||||||
|
X86_64.enc(inst.i32.any, *r.rc.rex(0xd3, rrr=rrr))
|
||||||
|
X86_64.enc(inst.i32.any, *r.rc(0xd3, rrr=rrr))
|
||||||
|
|
||||||
|
for inst, rrr in [
|
||||||
|
(base.ishl_imm, 4),
|
||||||
|
(base.ushr_imm, 5),
|
||||||
|
(base.sshr_imm, 7)]:
|
||||||
|
enc_i32_i64(inst, r.rib, 0xc1, rrr=rrr)
|
||||||
|
|
||||||
# Population count.
|
# Population count.
|
||||||
I32.enc(base.popcnt.i32, *r.urm(0xf3, 0x0f, 0xb8), isap=cfg.use_popcnt)
|
X86_32.enc(base.popcnt.i32, *r.urm(0xf3, 0x0f, 0xb8), isap=cfg.use_popcnt)
|
||||||
I64.enc(base.popcnt.i64, *r.urm.rex(0xf3, 0x0f, 0xb8, w=1),
|
X86_64.enc(base.popcnt.i64, *r.urm.rex(0xf3, 0x0f, 0xb8, w=1),
|
||||||
isap=cfg.use_popcnt)
|
isap=cfg.use_popcnt)
|
||||||
I64.enc(base.popcnt.i32, *r.urm.rex(0xf3, 0x0f, 0xb8), isap=cfg.use_popcnt)
|
X86_64.enc(base.popcnt.i32, *r.urm.rex(0xf3, 0x0f, 0xb8), isap=cfg.use_popcnt)
|
||||||
I64.enc(base.popcnt.i32, *r.urm(0xf3, 0x0f, 0xb8), isap=cfg.use_popcnt)
|
X86_64.enc(base.popcnt.i32, *r.urm(0xf3, 0x0f, 0xb8), isap=cfg.use_popcnt)
|
||||||
|
|
||||||
# Count leading zero bits.
|
# Count leading zero bits.
|
||||||
I32.enc(base.clz.i32, *r.urm(0xf3, 0x0f, 0xbd), isap=cfg.use_lzcnt)
|
X86_32.enc(base.clz.i32, *r.urm(0xf3, 0x0f, 0xbd), isap=cfg.use_lzcnt)
|
||||||
I64.enc(base.clz.i64, *r.urm.rex(0xf3, 0x0f, 0xbd, w=1),
|
X86_64.enc(base.clz.i64, *r.urm.rex(0xf3, 0x0f, 0xbd, w=1),
|
||||||
isap=cfg.use_lzcnt)
|
isap=cfg.use_lzcnt)
|
||||||
I64.enc(base.clz.i32, *r.urm.rex(0xf3, 0x0f, 0xbd), isap=cfg.use_lzcnt)
|
X86_64.enc(base.clz.i32, *r.urm.rex(0xf3, 0x0f, 0xbd), isap=cfg.use_lzcnt)
|
||||||
I64.enc(base.clz.i32, *r.urm(0xf3, 0x0f, 0xbd), isap=cfg.use_lzcnt)
|
X86_64.enc(base.clz.i32, *r.urm(0xf3, 0x0f, 0xbd), isap=cfg.use_lzcnt)
|
||||||
|
|
||||||
# Count trailing zero bits.
|
# Count trailing zero bits.
|
||||||
I32.enc(base.ctz.i32, *r.urm(0xf3, 0x0f, 0xbc), isap=cfg.use_bmi1)
|
X86_32.enc(base.ctz.i32, *r.urm(0xf3, 0x0f, 0xbc), isap=cfg.use_bmi1)
|
||||||
I64.enc(base.ctz.i64, *r.urm.rex(0xf3, 0x0f, 0xbc, w=1),
|
X86_64.enc(base.ctz.i64, *r.urm.rex(0xf3, 0x0f, 0xbc, w=1),
|
||||||
isap=cfg.use_bmi1)
|
isap=cfg.use_bmi1)
|
||||||
I64.enc(base.ctz.i32, *r.urm.rex(0xf3, 0x0f, 0xbc), isap=cfg.use_bmi1)
|
X86_64.enc(base.ctz.i32, *r.urm.rex(0xf3, 0x0f, 0xbc), isap=cfg.use_bmi1)
|
||||||
I64.enc(base.ctz.i32, *r.urm(0xf3, 0x0f, 0xbc), isap=cfg.use_bmi1)
|
X86_64.enc(base.ctz.i32, *r.urm(0xf3, 0x0f, 0xbc), isap=cfg.use_bmi1)
|
||||||
|
|
||||||
#
|
#
|
||||||
# Loads and stores.
|
# Loads and stores.
|
||||||
#
|
#
|
||||||
for recipe in [r.st, r.stDisp8, r.stDisp32]:
|
for recipe in [r.st, r.stDisp8, r.stDisp32]:
|
||||||
enc_i32_i64_ld_st(base.store, True, recipe, 0x89)
|
enc_i32_i64_ld_st(base.store, True, recipe, 0x89)
|
||||||
enc_i64(base.istore32.i64.any, recipe, 0x89)
|
enc_x86_64(base.istore32.i64.any, recipe, 0x89)
|
||||||
enc_i32_i64_ld_st(base.istore16, False, recipe, 0x66, 0x89)
|
enc_i32_i64_ld_st(base.istore16, False, recipe, 0x66, 0x89)
|
||||||
|
|
||||||
# Byte stores are more complicated because the registers they can address
|
# Byte stores are more complicated because the registers they can address
|
||||||
@@ -203,121 +214,121 @@ for recipe in [r.st, r.stDisp8, r.stDisp32]:
|
|||||||
# the corresponding st* recipes when a REX prefix is applied.
|
# the corresponding st* recipes when a REX prefix is applied.
|
||||||
for recipe in [r.st_abcd, r.stDisp8_abcd, r.stDisp32_abcd]:
|
for recipe in [r.st_abcd, r.stDisp8_abcd, r.stDisp32_abcd]:
|
||||||
enc_both(base.istore8.i32.any, recipe, 0x88)
|
enc_both(base.istore8.i32.any, recipe, 0x88)
|
||||||
enc_i64(base.istore8.i64.any, recipe, 0x88)
|
enc_x86_64(base.istore8.i64.any, recipe, 0x88)
|
||||||
|
|
||||||
enc_i32_i64(base.spill, r.spSib32, 0x89)
|
enc_i32_i64(base.spill, r.spillSib32, 0x89)
|
||||||
enc_i32_i64(base.regspill, r.rsp32, 0x89)
|
enc_i32_i64(base.regspill, r.regspill32, 0x89)
|
||||||
|
|
||||||
# Use a 32-bit write for spilling `b1` to avoid constraining the permitted
|
# Use a 32-bit write for spilling `b1` to avoid constraining the permitted
|
||||||
# registers.
|
# registers.
|
||||||
# See MIN_SPILL_SLOT_SIZE which makes this safe.
|
# See MIN_SPILL_SLOT_SIZE which makes this safe.
|
||||||
enc_both(base.spill.b1, r.spSib32, 0x89)
|
enc_both(base.spill.b1, r.spillSib32, 0x89)
|
||||||
enc_both(base.regspill.b1, r.rsp32, 0x89)
|
enc_both(base.regspill.b1, r.regspill32, 0x89)
|
||||||
|
|
||||||
for recipe in [r.ld, r.ldDisp8, r.ldDisp32]:
|
for recipe in [r.ld, r.ldDisp8, r.ldDisp32]:
|
||||||
enc_i32_i64_ld_st(base.load, True, recipe, 0x8b)
|
enc_i32_i64_ld_st(base.load, True, recipe, 0x8b)
|
||||||
enc_i64(base.uload32.i64, recipe, 0x8b)
|
enc_x86_64(base.uload32.i64, recipe, 0x8b)
|
||||||
I64.enc(base.sload32.i64, *recipe.rex(0x63, w=1))
|
X86_64.enc(base.sload32.i64, *recipe.rex(0x63, w=1))
|
||||||
enc_i32_i64_ld_st(base.uload16, True, recipe, 0x0f, 0xb7)
|
enc_i32_i64_ld_st(base.uload16, True, recipe, 0x0f, 0xb7)
|
||||||
enc_i32_i64_ld_st(base.sload16, True, recipe, 0x0f, 0xbf)
|
enc_i32_i64_ld_st(base.sload16, True, recipe, 0x0f, 0xbf)
|
||||||
enc_i32_i64_ld_st(base.uload8, True, recipe, 0x0f, 0xb6)
|
enc_i32_i64_ld_st(base.uload8, True, recipe, 0x0f, 0xb6)
|
||||||
enc_i32_i64_ld_st(base.sload8, True, recipe, 0x0f, 0xbe)
|
enc_i32_i64_ld_st(base.sload8, True, recipe, 0x0f, 0xbe)
|
||||||
|
|
||||||
enc_i32_i64(base.fill, r.fiSib32, 0x8b)
|
enc_i32_i64(base.fill, r.fillSib32, 0x8b)
|
||||||
enc_i32_i64(base.regfill, r.rfi32, 0x8b)
|
enc_i32_i64(base.regfill, r.regfill32, 0x8b)
|
||||||
|
|
||||||
# Load 32 bits from `b1` spill slots. See `spill.b1` above.
|
# Load 32 bits from `b1` spill slots. See `spill.b1` above.
|
||||||
enc_both(base.fill.b1, r.fiSib32, 0x8b)
|
enc_both(base.fill.b1, r.fillSib32, 0x8b)
|
||||||
enc_both(base.regfill.b1, r.rfi32, 0x8b)
|
enc_both(base.regfill.b1, r.regfill32, 0x8b)
|
||||||
|
|
||||||
# Push and Pop
|
# Push and Pop
|
||||||
I32.enc(x86.push.i32, *r.pushq(0x50))
|
X86_32.enc(x86.push.i32, *r.pushq(0x50))
|
||||||
enc_i64(x86.push.i64, r.pushq, 0x50)
|
enc_x86_64(x86.push.i64, r.pushq, 0x50)
|
||||||
|
|
||||||
I32.enc(x86.pop.i32, *r.popq(0x58))
|
X86_32.enc(x86.pop.i32, *r.popq(0x58))
|
||||||
enc_i64(x86.pop.i64, r.popq, 0x58)
|
enc_x86_64(x86.pop.i64, r.popq, 0x58)
|
||||||
|
|
||||||
# Copy Special
|
# Copy Special
|
||||||
I64.enc(base.copy_special, *r.copysp.rex(0x89, w=1))
|
X86_64.enc(base.copy_special, *r.copysp.rex(0x89, w=1))
|
||||||
I32.enc(base.copy_special, *r.copysp(0x89))
|
X86_32.enc(base.copy_special, *r.copysp(0x89))
|
||||||
|
|
||||||
# Adjust SP Imm
|
# Adjust SP Imm
|
||||||
I32.enc(base.adjust_sp_imm, *r.adjustsp8(0x83))
|
X86_32.enc(base.adjust_sp_imm, *r.adjustsp8(0x83))
|
||||||
I32.enc(base.adjust_sp_imm, *r.adjustsp32(0x81))
|
X86_32.enc(base.adjust_sp_imm, *r.adjustsp32(0x81))
|
||||||
I64.enc(base.adjust_sp_imm, *r.adjustsp8.rex(0x83, w=1))
|
X86_64.enc(base.adjust_sp_imm, *r.adjustsp8.rex(0x83, w=1))
|
||||||
I64.enc(base.adjust_sp_imm, *r.adjustsp32.rex(0x81, w=1))
|
X86_64.enc(base.adjust_sp_imm, *r.adjustsp32.rex(0x81, w=1))
|
||||||
|
|
||||||
#
|
#
|
||||||
# Float loads and stores.
|
# Float loads and stores.
|
||||||
#
|
#
|
||||||
|
|
||||||
enc_both(base.load.f32.any, r.fld, 0x66, 0x0f, 0x6e)
|
enc_both(base.load.f32.any, r.fld, 0xf3, 0x0f, 0x10)
|
||||||
enc_both(base.load.f32.any, r.fldDisp8, 0x66, 0x0f, 0x6e)
|
enc_both(base.load.f32.any, r.fldDisp8, 0xf3, 0x0f, 0x10)
|
||||||
enc_both(base.load.f32.any, r.fldDisp32, 0x66, 0x0f, 0x6e)
|
enc_both(base.load.f32.any, r.fldDisp32, 0xf3, 0x0f, 0x10)
|
||||||
|
|
||||||
enc_both(base.load.f64.any, r.fld, 0xf3, 0x0f, 0x7e)
|
enc_both(base.load.f64.any, r.fld, 0xf2, 0x0f, 0x10)
|
||||||
enc_both(base.load.f64.any, r.fldDisp8, 0xf3, 0x0f, 0x7e)
|
enc_both(base.load.f64.any, r.fldDisp8, 0xf2, 0x0f, 0x10)
|
||||||
enc_both(base.load.f64.any, r.fldDisp32, 0xf3, 0x0f, 0x7e)
|
enc_both(base.load.f64.any, r.fldDisp32, 0xf2, 0x0f, 0x10)
|
||||||
|
|
||||||
enc_both(base.store.f32.any, r.fst, 0x66, 0x0f, 0x7e)
|
enc_both(base.store.f32.any, r.fst, 0xf3, 0x0f, 0x11)
|
||||||
enc_both(base.store.f32.any, r.fstDisp8, 0x66, 0x0f, 0x7e)
|
enc_both(base.store.f32.any, r.fstDisp8, 0xf3, 0x0f, 0x11)
|
||||||
enc_both(base.store.f32.any, r.fstDisp32, 0x66, 0x0f, 0x7e)
|
enc_both(base.store.f32.any, r.fstDisp32, 0xf3, 0x0f, 0x11)
|
||||||
|
|
||||||
enc_both(base.store.f64.any, r.fst, 0x66, 0x0f, 0xd6)
|
enc_both(base.store.f64.any, r.fst, 0xf2, 0x0f, 0x11)
|
||||||
enc_both(base.store.f64.any, r.fstDisp8, 0x66, 0x0f, 0xd6)
|
enc_both(base.store.f64.any, r.fstDisp8, 0xf2, 0x0f, 0x11)
|
||||||
enc_both(base.store.f64.any, r.fstDisp32, 0x66, 0x0f, 0xd6)
|
enc_both(base.store.f64.any, r.fstDisp32, 0xf2, 0x0f, 0x11)
|
||||||
|
|
||||||
enc_both(base.fill.f32, r.ffiSib32, 0x66, 0x0f, 0x6e)
|
enc_both(base.fill.f32, r.ffillSib32, 0xf3, 0x0f, 0x10)
|
||||||
enc_both(base.regfill.f32, r.frfi32, 0x66, 0x0f, 0x6e)
|
enc_both(base.regfill.f32, r.fregfill32, 0xf3, 0x0f, 0x10)
|
||||||
enc_both(base.fill.f64, r.ffiSib32, 0xf3, 0x0f, 0x7e)
|
enc_both(base.fill.f64, r.ffillSib32, 0xf2, 0x0f, 0x10)
|
||||||
enc_both(base.regfill.f64, r.frfi32, 0xf3, 0x0f, 0x7e)
|
enc_both(base.regfill.f64, r.fregfill32, 0xf2, 0x0f, 0x10)
|
||||||
|
|
||||||
enc_both(base.spill.f32, r.fspSib32, 0x66, 0x0f, 0x7e)
|
enc_both(base.spill.f32, r.fspillSib32, 0xf3, 0x0f, 0x11)
|
||||||
enc_both(base.regspill.f32, r.frsp32, 0x66, 0x0f, 0x7e)
|
enc_both(base.regspill.f32, r.fregspill32, 0xf3, 0x0f, 0x11)
|
||||||
enc_both(base.spill.f64, r.fspSib32, 0x66, 0x0f, 0xd6)
|
enc_both(base.spill.f64, r.fspillSib32, 0xf2, 0x0f, 0x11)
|
||||||
enc_both(base.regspill.f64, r.frsp32, 0x66, 0x0f, 0xd6)
|
enc_both(base.regspill.f64, r.fregspill32, 0xf2, 0x0f, 0x11)
|
||||||
|
|
||||||
#
|
#
|
||||||
# Function addresses.
|
# Function addresses.
|
||||||
#
|
#
|
||||||
|
|
||||||
I32.enc(base.func_addr.i32, *r.fnaddr4(0xb8),
|
X86_32.enc(base.func_addr.i32, *r.fnaddr4(0xb8),
|
||||||
isap=Not(allones_funcaddrs))
|
isap=Not(allones_funcaddrs))
|
||||||
I64.enc(base.func_addr.i64, *r.fnaddr8.rex(0xb8, w=1),
|
X86_64.enc(base.func_addr.i64, *r.fnaddr8.rex(0xb8, w=1),
|
||||||
isap=And(Not(allones_funcaddrs), Not(is_pic)))
|
isap=And(Not(allones_funcaddrs), Not(is_pic)))
|
||||||
|
|
||||||
I32.enc(base.func_addr.i32, *r.allones_fnaddr4(0xb8),
|
X86_32.enc(base.func_addr.i32, *r.allones_fnaddr4(0xb8),
|
||||||
isap=allones_funcaddrs)
|
isap=allones_funcaddrs)
|
||||||
I64.enc(base.func_addr.i64, *r.allones_fnaddr8.rex(0xb8, w=1),
|
X86_64.enc(base.func_addr.i64, *r.allones_fnaddr8.rex(0xb8, w=1),
|
||||||
isap=And(allones_funcaddrs, Not(is_pic)))
|
isap=And(allones_funcaddrs, Not(is_pic)))
|
||||||
|
|
||||||
I64.enc(base.func_addr.i64, *r.got_fnaddr8.rex(0x8b, w=1),
|
X86_64.enc(base.func_addr.i64, *r.got_fnaddr8.rex(0x8b, w=1),
|
||||||
isap=is_pic)
|
isap=is_pic)
|
||||||
|
|
||||||
#
|
#
|
||||||
# Global addresses.
|
# Global addresses.
|
||||||
#
|
#
|
||||||
|
|
||||||
I32.enc(base.globalsym_addr.i32, *r.gvaddr4(0xb8))
|
X86_32.enc(base.globalsym_addr.i32, *r.gvaddr4(0xb8))
|
||||||
I64.enc(base.globalsym_addr.i64, *r.gvaddr8.rex(0xb8, w=1),
|
X86_64.enc(base.globalsym_addr.i64, *r.gvaddr8.rex(0xb8, w=1),
|
||||||
isap=Not(is_pic))
|
isap=Not(is_pic))
|
||||||
|
|
||||||
I64.enc(base.globalsym_addr.i64, *r.got_gvaddr8.rex(0x8b, w=1),
|
X86_64.enc(base.globalsym_addr.i64, *r.got_gvaddr8.rex(0x8b, w=1),
|
||||||
isap=is_pic)
|
isap=is_pic)
|
||||||
|
|
||||||
#
|
#
|
||||||
# Call/return
|
# Call/return
|
||||||
#
|
#
|
||||||
I32.enc(base.call, *r.call_id(0xe8))
|
X86_32.enc(base.call, *r.call_id(0xe8))
|
||||||
I64.enc(base.call, *r.call_id(0xe8), isap=Not(is_pic))
|
X86_64.enc(base.call, *r.call_id(0xe8), isap=Not(is_pic))
|
||||||
I64.enc(base.call, *r.call_plt_id(0xe8), isap=is_pic)
|
X86_64.enc(base.call, *r.call_plt_id(0xe8), isap=is_pic)
|
||||||
|
|
||||||
I32.enc(base.call_indirect.i32, *r.call_r(0xff, rrr=2))
|
X86_32.enc(base.call_indirect.i32, *r.call_r(0xff, rrr=2))
|
||||||
I64.enc(base.call_indirect.i64, *r.call_r.rex(0xff, rrr=2))
|
X86_64.enc(base.call_indirect.i64, *r.call_r.rex(0xff, rrr=2))
|
||||||
I64.enc(base.call_indirect.i64, *r.call_r(0xff, rrr=2))
|
X86_64.enc(base.call_indirect.i64, *r.call_r(0xff, rrr=2))
|
||||||
|
|
||||||
I32.enc(base.x_return, *r.ret(0xc3))
|
X86_32.enc(base.x_return, *r.ret(0xc3))
|
||||||
I64.enc(base.x_return, *r.ret(0xc3))
|
X86_64.enc(base.x_return, *r.ret(0xc3))
|
||||||
|
|
||||||
#
|
#
|
||||||
# Branches
|
# Branches
|
||||||
@@ -341,10 +352,10 @@ enc_i32_i64(base.brnz, r.tjccd, 0x85)
|
|||||||
# Branch on a b1 value in a register only looks at the low 8 bits. See also
|
# Branch on a b1 value in a register only looks at the low 8 bits. See also
|
||||||
# bint encodings below.
|
# bint encodings below.
|
||||||
#
|
#
|
||||||
# Start with the worst-case encoding for I32 only. The register allocator can't
|
# Start with the worst-case encoding for X86_32 only. The register allocator
|
||||||
# handle a branch with an ABCD-constrained operand.
|
# can't handle a branch with an ABCD-constrained operand.
|
||||||
I32.enc(base.brz.b1, *r.t8jccd_long(0x84))
|
X86_32.enc(base.brz.b1, *r.t8jccd_long(0x84))
|
||||||
I32.enc(base.brnz.b1, *r.t8jccd_long(0x85))
|
X86_32.enc(base.brnz.b1, *r.t8jccd_long(0x85))
|
||||||
|
|
||||||
enc_both(base.brz.b1, r.t8jccb_abcd, 0x74)
|
enc_both(base.brz.b1, r.t8jccb_abcd, 0x74)
|
||||||
enc_both(base.brz.b1, r.t8jccd_abcd, 0x84)
|
enc_both(base.brz.b1, r.t8jccd_abcd, 0x84)
|
||||||
@@ -354,26 +365,28 @@ enc_both(base.brnz.b1, r.t8jccd_abcd, 0x85)
|
|||||||
#
|
#
|
||||||
# Trap as ud2
|
# Trap as ud2
|
||||||
#
|
#
|
||||||
I32.enc(base.trap, *r.trap(0x0f, 0x0b))
|
X86_32.enc(base.trap, *r.trap(0x0f, 0x0b))
|
||||||
I64.enc(base.trap, *r.trap(0x0f, 0x0b))
|
X86_64.enc(base.trap, *r.trap(0x0f, 0x0b))
|
||||||
|
|
||||||
# Using a standard EncRecipe, not the TailRecipe.
|
# Using a standard EncRecipe, not the TailRecipe.
|
||||||
I32.enc(base.trapif, r.trapif, 0)
|
X86_32.enc(base.trapif, r.trapif, 0)
|
||||||
I64.enc(base.trapif, r.trapif, 0)
|
X86_64.enc(base.trapif, r.trapif, 0)
|
||||||
I32.enc(base.trapff, r.trapff, 0)
|
X86_32.enc(base.trapff, r.trapff, 0)
|
||||||
I64.enc(base.trapff, r.trapff, 0)
|
X86_64.enc(base.trapff, r.trapff, 0)
|
||||||
|
|
||||||
#
|
#
|
||||||
# Comparisons
|
# Comparisons
|
||||||
#
|
#
|
||||||
enc_i32_i64(base.icmp, r.icscc, 0x39)
|
enc_i32_i64(base.icmp, r.icscc, 0x39)
|
||||||
|
enc_i32_i64(base.icmp_imm, r.icsccib, 0x83, rrr=7)
|
||||||
|
enc_i32_i64(base.icmp_imm, r.icsccid, 0x81, rrr=7)
|
||||||
enc_i32_i64(base.ifcmp, r.rcmp, 0x39)
|
enc_i32_i64(base.ifcmp, r.rcmp, 0x39)
|
||||||
enc_i32_i64(base.ifcmp_imm, r.rcmpib, 0x83, rrr=7)
|
enc_i32_i64(base.ifcmp_imm, r.rcmpib, 0x83, rrr=7)
|
||||||
enc_i32_i64(base.ifcmp_imm, r.rcmpid, 0x81, rrr=7)
|
enc_i32_i64(base.ifcmp_imm, r.rcmpid, 0x81, rrr=7)
|
||||||
# TODO: We could special-case ifcmp_imm(x, 0) to TEST(x, x).
|
# TODO: We could special-case ifcmp_imm(x, 0) to TEST(x, x).
|
||||||
|
|
||||||
I32.enc(base.ifcmp_sp.i32, *r.rcmp_sp(0x39))
|
X86_32.enc(base.ifcmp_sp.i32, *r.rcmp_sp(0x39))
|
||||||
I64.enc(base.ifcmp_sp.i64, *r.rcmp_sp.rex(0x39, w=1))
|
X86_64.enc(base.ifcmp_sp.i64, *r.rcmp_sp.rex(0x39, w=1))
|
||||||
|
|
||||||
#
|
#
|
||||||
# Convert flags to bool.
|
# Convert flags to bool.
|
||||||
@@ -398,66 +411,68 @@ enc_i32_i64(x86.bsr, r.bsf_and_bsr, 0x0F, 0xBD)
|
|||||||
#
|
#
|
||||||
# This assumes that b1 is represented as an 8-bit low register with the value 0
|
# This assumes that b1 is represented as an 8-bit low register with the value 0
|
||||||
# or 1.
|
# or 1.
|
||||||
I32.enc(base.bint.i32.b1, *r.urm_abcd(0x0f, 0xb6))
|
#
|
||||||
I64.enc(base.bint.i64.b1, *r.urm.rex(0x0f, 0xb6)) # zext to i64 implicit.
|
# Encode movzbq as movzbl, because it's equivalent and shorter.
|
||||||
I64.enc(base.bint.i64.b1, *r.urm_abcd(0x0f, 0xb6)) # zext to i64 implicit.
|
X86_32.enc(base.bint.i32.b1, *r.urm_noflags_abcd(0x0f, 0xb6))
|
||||||
I64.enc(base.bint.i32.b1, *r.urm.rex(0x0f, 0xb6))
|
X86_64.enc(base.bint.i64.b1, *r.urm_noflags.rex(0x0f, 0xb6))
|
||||||
I64.enc(base.bint.i32.b1, *r.urm_abcd(0x0f, 0xb6))
|
X86_64.enc(base.bint.i64.b1, *r.urm_noflags_abcd(0x0f, 0xb6))
|
||||||
|
X86_64.enc(base.bint.i32.b1, *r.urm_noflags.rex(0x0f, 0xb6))
|
||||||
|
X86_64.enc(base.bint.i32.b1, *r.urm_noflags_abcd(0x0f, 0xb6))
|
||||||
|
|
||||||
# Numerical conversions.
|
# Numerical conversions.
|
||||||
|
|
||||||
# Reducing an integer is a no-op.
|
# Reducing an integer is a no-op.
|
||||||
I32.enc(base.ireduce.i8.i32, r.null, 0)
|
X86_32.enc(base.ireduce.i8.i32, r.null, 0)
|
||||||
I32.enc(base.ireduce.i16.i32, r.null, 0)
|
X86_32.enc(base.ireduce.i16.i32, r.null, 0)
|
||||||
I64.enc(base.ireduce.i8.i32, r.null, 0)
|
X86_64.enc(base.ireduce.i8.i32, r.null, 0)
|
||||||
I64.enc(base.ireduce.i16.i32, r.null, 0)
|
X86_64.enc(base.ireduce.i16.i32, r.null, 0)
|
||||||
I64.enc(base.ireduce.i8.i64, r.null, 0)
|
X86_64.enc(base.ireduce.i8.i64, r.null, 0)
|
||||||
I64.enc(base.ireduce.i16.i64, r.null, 0)
|
X86_64.enc(base.ireduce.i16.i64, r.null, 0)
|
||||||
I64.enc(base.ireduce.i32.i64, r.null, 0)
|
X86_64.enc(base.ireduce.i32.i64, r.null, 0)
|
||||||
|
|
||||||
# TODO: Add encodings for cbw, cwde, cdqe, which are sign-extending
|
# TODO: Add encodings for cbw, cwde, cdqe, which are sign-extending
|
||||||
# instructions for %al/%ax/%eax to %ax/%eax/%rax.
|
# instructions for %al/%ax/%eax to %ax/%eax/%rax.
|
||||||
|
|
||||||
# movsbl
|
# movsbl
|
||||||
I32.enc(base.sextend.i32.i8, *r.urm(0x0f, 0xbe))
|
X86_32.enc(base.sextend.i32.i8, *r.urm_noflags(0x0f, 0xbe))
|
||||||
I64.enc(base.sextend.i32.i8, *r.urm.rex(0x0f, 0xbe))
|
X86_64.enc(base.sextend.i32.i8, *r.urm_noflags.rex(0x0f, 0xbe))
|
||||||
I64.enc(base.sextend.i32.i8, *r.urm(0x0f, 0xbe))
|
X86_64.enc(base.sextend.i32.i8, *r.urm_noflags(0x0f, 0xbe))
|
||||||
|
|
||||||
# movswl
|
# movswl
|
||||||
I32.enc(base.sextend.i32.i16, *r.urm(0x0f, 0xbf))
|
X86_32.enc(base.sextend.i32.i16, *r.urm_noflags(0x0f, 0xbf))
|
||||||
I64.enc(base.sextend.i32.i16, *r.urm.rex(0x0f, 0xbf))
|
X86_64.enc(base.sextend.i32.i16, *r.urm_noflags.rex(0x0f, 0xbf))
|
||||||
I64.enc(base.sextend.i32.i16, *r.urm(0x0f, 0xbf))
|
X86_64.enc(base.sextend.i32.i16, *r.urm_noflags(0x0f, 0xbf))
|
||||||
|
|
||||||
# movsbq
|
# movsbq
|
||||||
I64.enc(base.sextend.i64.i8, *r.urm.rex(0x0f, 0xbe, w=1))
|
X86_64.enc(base.sextend.i64.i8, *r.urm_noflags.rex(0x0f, 0xbe, w=1))
|
||||||
|
|
||||||
# movswq
|
# movswq
|
||||||
I64.enc(base.sextend.i64.i16, *r.urm.rex(0x0f, 0xbf, w=1))
|
X86_64.enc(base.sextend.i64.i16, *r.urm_noflags.rex(0x0f, 0xbf, w=1))
|
||||||
|
|
||||||
# movslq
|
# movslq
|
||||||
I64.enc(base.sextend.i64.i32, *r.urm.rex(0x63, w=1))
|
X86_64.enc(base.sextend.i64.i32, *r.urm_noflags.rex(0x63, w=1))
|
||||||
|
|
||||||
# movzbl
|
# movzbl
|
||||||
I32.enc(base.uextend.i32.i8, *r.urm(0x0f, 0xb6))
|
X86_32.enc(base.uextend.i32.i8, *r.urm_noflags(0x0f, 0xb6))
|
||||||
I64.enc(base.uextend.i32.i8, *r.urm.rex(0x0f, 0xb6))
|
X86_64.enc(base.uextend.i32.i8, *r.urm_noflags.rex(0x0f, 0xb6))
|
||||||
I64.enc(base.uextend.i32.i8, *r.urm(0x0f, 0xb6))
|
X86_64.enc(base.uextend.i32.i8, *r.urm_noflags(0x0f, 0xb6))
|
||||||
|
|
||||||
# movzwl
|
# movzwl
|
||||||
I32.enc(base.uextend.i32.i16, *r.urm(0x0f, 0xb7))
|
X86_32.enc(base.uextend.i32.i16, *r.urm_noflags(0x0f, 0xb7))
|
||||||
I64.enc(base.uextend.i32.i16, *r.urm.rex(0x0f, 0xb7))
|
X86_64.enc(base.uextend.i32.i16, *r.urm_noflags.rex(0x0f, 0xb7))
|
||||||
I64.enc(base.uextend.i32.i16, *r.urm(0x0f, 0xb7))
|
X86_64.enc(base.uextend.i32.i16, *r.urm_noflags(0x0f, 0xb7))
|
||||||
|
|
||||||
# movzbq, encoded as movzbl because it's equivalent and shorter
|
# movzbq, encoded as movzbl because it's equivalent and shorter
|
||||||
I64.enc(base.uextend.i64.i8, *r.urm.rex(0x0f, 0xb6))
|
X86_64.enc(base.uextend.i64.i8, *r.urm_noflags.rex(0x0f, 0xb6))
|
||||||
I64.enc(base.uextend.i64.i8, *r.urm(0x0f, 0xb6))
|
X86_64.enc(base.uextend.i64.i8, *r.urm_noflags(0x0f, 0xb6))
|
||||||
|
|
||||||
# movzwq, encoded as movzwl because it's equivalent and shorter
|
# movzwq, encoded as movzwl because it's equivalent and shorter
|
||||||
I64.enc(base.uextend.i64.i16, *r.urm.rex(0x0f, 0xb7))
|
X86_64.enc(base.uextend.i64.i16, *r.urm_noflags.rex(0x0f, 0xb7))
|
||||||
I64.enc(base.uextend.i64.i16, *r.urm(0x0f, 0xb7))
|
X86_64.enc(base.uextend.i64.i16, *r.urm_noflags(0x0f, 0xb7))
|
||||||
|
|
||||||
# A 32-bit register copy clears the high 32 bits.
|
# A 32-bit register copy clears the high 32 bits.
|
||||||
I64.enc(base.uextend.i64.i32, *r.umr.rex(0x89))
|
X86_64.enc(base.uextend.i64.i32, *r.umr.rex(0x89))
|
||||||
I64.enc(base.uextend.i64.i32, *r.umr(0x89))
|
X86_64.enc(base.uextend.i64.i32, *r.umr(0x89))
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -469,8 +484,8 @@ enc_both(base.bitcast.f32.i32, r.frurm, 0x66, 0x0f, 0x6e)
|
|||||||
enc_both(base.bitcast.i32.f32, r.rfumr, 0x66, 0x0f, 0x7e)
|
enc_both(base.bitcast.i32.f32, r.rfumr, 0x66, 0x0f, 0x7e)
|
||||||
|
|
||||||
# movq
|
# movq
|
||||||
I64.enc(base.bitcast.f64.i64, *r.frurm.rex(0x66, 0x0f, 0x6e, w=1))
|
X86_64.enc(base.bitcast.f64.i64, *r.frurm.rex(0x66, 0x0f, 0x6e, w=1))
|
||||||
I64.enc(base.bitcast.i64.f64, *r.rfumr.rex(0x66, 0x0f, 0x7e, w=1))
|
X86_64.enc(base.bitcast.i64.f64, *r.rfumr.rex(0x66, 0x0f, 0x7e, w=1))
|
||||||
|
|
||||||
# movaps
|
# movaps
|
||||||
enc_both(base.copy.f32, r.furm, 0x0f, 0x28)
|
enc_both(base.copy.f32, r.furm, 0x0f, 0x28)
|
||||||
@@ -492,11 +507,11 @@ enc_both(base.fdemote.f32.f64, r.furm, 0xf2, 0x0f, 0x5a)
|
|||||||
|
|
||||||
# cvttss2si
|
# cvttss2si
|
||||||
enc_both(x86.cvtt2si.i32.f32, r.rfurm, 0xf3, 0x0f, 0x2c)
|
enc_both(x86.cvtt2si.i32.f32, r.rfurm, 0xf3, 0x0f, 0x2c)
|
||||||
I64.enc(x86.cvtt2si.i64.f32, *r.rfurm.rex(0xf3, 0x0f, 0x2c, w=1))
|
X86_64.enc(x86.cvtt2si.i64.f32, *r.rfurm.rex(0xf3, 0x0f, 0x2c, w=1))
|
||||||
|
|
||||||
# cvttsd2si
|
# cvttsd2si
|
||||||
enc_both(x86.cvtt2si.i32.f64, r.rfurm, 0xf2, 0x0f, 0x2c)
|
enc_both(x86.cvtt2si.i32.f64, r.rfurm, 0xf2, 0x0f, 0x2c)
|
||||||
I64.enc(x86.cvtt2si.i64.f64, *r.rfurm.rex(0xf2, 0x0f, 0x2c, w=1))
|
X86_64.enc(x86.cvtt2si.i64.f64, *r.rfurm.rex(0xf2, 0x0f, 0x2c, w=1))
|
||||||
|
|
||||||
# Exact square roots.
|
# Exact square roots.
|
||||||
enc_both(base.sqrt.f32, r.furm, 0xf3, 0x0f, 0x51)
|
enc_both(base.sqrt.f32, r.furm, 0xf3, 0x0f, 0x51)
|
||||||
|
|||||||
@@ -5,9 +5,11 @@ from __future__ import absolute_import
|
|||||||
from cdsl.isa import EncRecipe
|
from cdsl.isa import EncRecipe
|
||||||
from cdsl.predicates import IsSignedInt, IsEqual, Or
|
from cdsl.predicates import IsSignedInt, IsEqual, Or
|
||||||
from cdsl.registers import RegClass
|
from cdsl.registers import RegClass
|
||||||
from base.formats import Unary, UnaryImm, Binary, BinaryImm, MultiAry, NullAry
|
from base.formats import Unary, UnaryImm, UnaryBool, Binary, BinaryImm
|
||||||
|
from base.formats import MultiAry, NullAry
|
||||||
from base.formats import Trap, Call, IndirectCall, Store, Load
|
from base.formats import Trap, Call, IndirectCall, Store, Load
|
||||||
from base.formats import IntCompare, FloatCompare, IntCond, FloatCond
|
from base.formats import IntCompare, IntCompareImm, FloatCompare
|
||||||
|
from base.formats import IntCond, FloatCond
|
||||||
from base.formats import IntSelect, IntCondTrap, FloatCondTrap
|
from base.formats import IntSelect, IntCondTrap, FloatCondTrap
|
||||||
from base.formats import Jump, Branch, BranchInt, BranchFloat
|
from base.formats import Jump, Branch, BranchInt, BranchFloat
|
||||||
from base.formats import Ternary, FuncAddr, UnaryGlobalVar
|
from base.formats import Ternary, FuncAddr, UnaryGlobalVar
|
||||||
@@ -277,23 +279,27 @@ null = EncRecipe('null', Unary, size=0, ins=GPR, outs=0, emit='')
|
|||||||
# XX opcode, no ModR/M.
|
# XX opcode, no ModR/M.
|
||||||
trap = TailRecipe(
|
trap = TailRecipe(
|
||||||
'trap', Trap, size=0, ins=(), outs=(),
|
'trap', Trap, size=0, ins=(), outs=(),
|
||||||
emit='PUT_OP(bits, BASE_REX, sink);')
|
emit='''
|
||||||
|
sink.trap(code, func.srclocs[inst]);
|
||||||
|
PUT_OP(bits, BASE_REX, sink);
|
||||||
|
''')
|
||||||
|
|
||||||
# Macro: conditional jump over a ud2.
|
# Macro: conditional jump over a ud2.
|
||||||
trapif = EncRecipe(
|
trapif = EncRecipe(
|
||||||
'trapif', IntCondTrap, size=4, ins=FLAG.eflags, outs=(),
|
'trapif', IntCondTrap, size=4, ins=FLAG.rflags, outs=(),
|
||||||
clobbers_flags=False,
|
clobbers_flags=False,
|
||||||
emit='''
|
emit='''
|
||||||
// Jump over a 2-byte ud2.
|
// Jump over a 2-byte ud2.
|
||||||
sink.put1(0x70 | (icc2opc(cond.inverse()) as u8));
|
sink.put1(0x70 | (icc2opc(cond.inverse()) as u8));
|
||||||
sink.put1(2);
|
sink.put1(2);
|
||||||
// ud2.
|
// ud2.
|
||||||
|
sink.trap(code, func.srclocs[inst]);
|
||||||
sink.put1(0x0f);
|
sink.put1(0x0f);
|
||||||
sink.put1(0x0b);
|
sink.put1(0x0b);
|
||||||
''')
|
''')
|
||||||
|
|
||||||
trapff = EncRecipe(
|
trapff = EncRecipe(
|
||||||
'trapff', FloatCondTrap, size=4, ins=FLAG.eflags, outs=(),
|
'trapff', FloatCondTrap, size=4, ins=FLAG.rflags, outs=(),
|
||||||
clobbers_flags=False,
|
clobbers_flags=False,
|
||||||
instp=floatccs(FloatCondTrap),
|
instp=floatccs(FloatCondTrap),
|
||||||
emit='''
|
emit='''
|
||||||
@@ -301,6 +307,7 @@ trapff = EncRecipe(
|
|||||||
sink.put1(0x70 | (fcc2opc(cond.inverse()) as u8));
|
sink.put1(0x70 | (fcc2opc(cond.inverse()) as u8));
|
||||||
sink.put1(2);
|
sink.put1(2);
|
||||||
// ud2.
|
// ud2.
|
||||||
|
sink.trap(code, func.srclocs[inst]);
|
||||||
sink.put1(0x0f);
|
sink.put1(0x0f);
|
||||||
sink.put1(0x0b);
|
sink.put1(0x0b);
|
||||||
''')
|
''')
|
||||||
@@ -358,7 +365,7 @@ rfumr = TailRecipe(
|
|||||||
''')
|
''')
|
||||||
|
|
||||||
# XX /r, but for a unary operator with separate input/output register.
|
# XX /r, but for a unary operator with separate input/output register.
|
||||||
# RM form.
|
# RM form. Clobbers FLAGS.
|
||||||
urm = TailRecipe(
|
urm = TailRecipe(
|
||||||
'urm', Unary, size=1, ins=GPR, outs=GPR,
|
'urm', Unary, size=1, ins=GPR, outs=GPR,
|
||||||
emit='''
|
emit='''
|
||||||
@@ -366,10 +373,19 @@ urm = TailRecipe(
|
|||||||
modrm_rr(in_reg0, out_reg0, sink);
|
modrm_rr(in_reg0, out_reg0, sink);
|
||||||
''')
|
''')
|
||||||
|
|
||||||
# XX /r. Same as urm, but input limited to ABCD.
|
# XX /r. Same as urm, but doesn't clobber FLAGS.
|
||||||
urm_abcd = TailRecipe(
|
urm_noflags = TailRecipe(
|
||||||
'urm_abcd', Unary, size=1, ins=ABCD, outs=GPR,
|
'urm_noflags', Unary, size=1, ins=GPR, outs=GPR,
|
||||||
when_prefixed=urm,
|
clobbers_flags=False,
|
||||||
|
emit='''
|
||||||
|
PUT_OP(bits, rex2(in_reg0, out_reg0), sink);
|
||||||
|
modrm_rr(in_reg0, out_reg0, sink);
|
||||||
|
''')
|
||||||
|
|
||||||
|
# XX /r. Same as urm_noflags, but input limited to ABCD.
|
||||||
|
urm_noflags_abcd = TailRecipe(
|
||||||
|
'urm_noflags_abcd', Unary, size=1, ins=ABCD, outs=GPR,
|
||||||
|
when_prefixed=urm_noflags,
|
||||||
emit='''
|
emit='''
|
||||||
PUT_OP(bits, rex2(in_reg0, out_reg0), sink);
|
PUT_OP(bits, rex2(in_reg0, out_reg0), sink);
|
||||||
modrm_rr(in_reg0, out_reg0, sink);
|
modrm_rr(in_reg0, out_reg0, sink);
|
||||||
@@ -449,6 +465,7 @@ div = TailRecipe(
|
|||||||
'div', Ternary, size=1,
|
'div', Ternary, size=1,
|
||||||
ins=(GPR.rax, GPR.rdx, GPR), outs=(GPR.rax, GPR.rdx),
|
ins=(GPR.rax, GPR.rdx, GPR), outs=(GPR.rax, GPR.rdx),
|
||||||
emit='''
|
emit='''
|
||||||
|
sink.trap(TrapCode::IntegerDivisionByZero, func.srclocs[inst]);
|
||||||
PUT_OP(bits, rex1(in_reg2), sink);
|
PUT_OP(bits, rex1(in_reg2), sink);
|
||||||
modrm_r_bits(in_reg2, bits, sink);
|
modrm_r_bits(in_reg2, bits, sink);
|
||||||
''')
|
''')
|
||||||
@@ -506,6 +523,17 @@ puid = TailRecipe(
|
|||||||
sink.put4(imm as u32);
|
sink.put4(imm as u32);
|
||||||
''')
|
''')
|
||||||
|
|
||||||
|
# XX+rd id unary with bool immediate. Note no recipe predicate.
|
||||||
|
puid_bool = TailRecipe(
|
||||||
|
'puid_bool', UnaryBool, size=4, ins=(), outs=GPR,
|
||||||
|
emit='''
|
||||||
|
// The destination register is encoded in the low bits of the opcode.
|
||||||
|
// No ModR/M.
|
||||||
|
PUT_OP(bits | (out_reg0 & 7), rex1(out_reg0), sink);
|
||||||
|
let imm: u32 = if imm.into() { 1 } else { 0 };
|
||||||
|
sink.put4(imm);
|
||||||
|
''')
|
||||||
|
|
||||||
# XX+rd iq unary with 64-bit immediate.
|
# XX+rd iq unary with 64-bit immediate.
|
||||||
puiq = TailRecipe(
|
puiq = TailRecipe(
|
||||||
'puiq', UnaryImm, size=8, ins=(), outs=GPR,
|
'puiq', UnaryImm, size=8, ins=(), outs=GPR,
|
||||||
@@ -666,6 +694,9 @@ st = TailRecipe(
|
|||||||
instp=IsEqual(Store.offset, 0),
|
instp=IsEqual(Store.offset, 0),
|
||||||
clobbers_flags=False,
|
clobbers_flags=False,
|
||||||
emit='''
|
emit='''
|
||||||
|
if !flags.notrap() {
|
||||||
|
sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
|
||||||
|
}
|
||||||
PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
|
PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
|
||||||
modrm_rm(in_reg1, in_reg0, sink);
|
modrm_rm(in_reg1, in_reg0, sink);
|
||||||
''')
|
''')
|
||||||
@@ -678,6 +709,9 @@ st_abcd = TailRecipe(
|
|||||||
when_prefixed=st,
|
when_prefixed=st,
|
||||||
clobbers_flags=False,
|
clobbers_flags=False,
|
||||||
emit='''
|
emit='''
|
||||||
|
if !flags.notrap() {
|
||||||
|
sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
|
||||||
|
}
|
||||||
PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
|
PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
|
||||||
modrm_rm(in_reg1, in_reg0, sink);
|
modrm_rm(in_reg1, in_reg0, sink);
|
||||||
''')
|
''')
|
||||||
@@ -688,6 +722,9 @@ fst = TailRecipe(
|
|||||||
instp=IsEqual(Store.offset, 0),
|
instp=IsEqual(Store.offset, 0),
|
||||||
clobbers_flags=False,
|
clobbers_flags=False,
|
||||||
emit='''
|
emit='''
|
||||||
|
if !flags.notrap() {
|
||||||
|
sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
|
||||||
|
}
|
||||||
PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
|
PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
|
||||||
modrm_rm(in_reg1, in_reg0, sink);
|
modrm_rm(in_reg1, in_reg0, sink);
|
||||||
''')
|
''')
|
||||||
@@ -698,6 +735,9 @@ stDisp8 = TailRecipe(
|
|||||||
instp=IsSignedInt(Store.offset, 8),
|
instp=IsSignedInt(Store.offset, 8),
|
||||||
clobbers_flags=False,
|
clobbers_flags=False,
|
||||||
emit='''
|
emit='''
|
||||||
|
if !flags.notrap() {
|
||||||
|
sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
|
||||||
|
}
|
||||||
PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
|
PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
|
||||||
modrm_disp8(in_reg1, in_reg0, sink);
|
modrm_disp8(in_reg1, in_reg0, sink);
|
||||||
let offset: i32 = offset.into();
|
let offset: i32 = offset.into();
|
||||||
@@ -709,6 +749,9 @@ stDisp8_abcd = TailRecipe(
|
|||||||
when_prefixed=stDisp8,
|
when_prefixed=stDisp8,
|
||||||
clobbers_flags=False,
|
clobbers_flags=False,
|
||||||
emit='''
|
emit='''
|
||||||
|
if !flags.notrap() {
|
||||||
|
sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
|
||||||
|
}
|
||||||
PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
|
PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
|
||||||
modrm_disp8(in_reg1, in_reg0, sink);
|
modrm_disp8(in_reg1, in_reg0, sink);
|
||||||
let offset: i32 = offset.into();
|
let offset: i32 = offset.into();
|
||||||
@@ -719,6 +762,9 @@ fstDisp8 = TailRecipe(
|
|||||||
instp=IsSignedInt(Store.offset, 8),
|
instp=IsSignedInt(Store.offset, 8),
|
||||||
clobbers_flags=False,
|
clobbers_flags=False,
|
||||||
emit='''
|
emit='''
|
||||||
|
if !flags.notrap() {
|
||||||
|
sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
|
||||||
|
}
|
||||||
PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
|
PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
|
||||||
modrm_disp8(in_reg1, in_reg0, sink);
|
modrm_disp8(in_reg1, in_reg0, sink);
|
||||||
let offset: i32 = offset.into();
|
let offset: i32 = offset.into();
|
||||||
@@ -730,6 +776,9 @@ stDisp32 = TailRecipe(
|
|||||||
'stDisp32', Store, size=5, ins=(GPR, GPR_DEREF_SAFE), outs=(),
|
'stDisp32', Store, size=5, ins=(GPR, GPR_DEREF_SAFE), outs=(),
|
||||||
clobbers_flags=False,
|
clobbers_flags=False,
|
||||||
emit='''
|
emit='''
|
||||||
|
if !flags.notrap() {
|
||||||
|
sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
|
||||||
|
}
|
||||||
PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
|
PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
|
||||||
modrm_disp32(in_reg1, in_reg0, sink);
|
modrm_disp32(in_reg1, in_reg0, sink);
|
||||||
let offset: i32 = offset.into();
|
let offset: i32 = offset.into();
|
||||||
@@ -740,6 +789,9 @@ stDisp32_abcd = TailRecipe(
|
|||||||
when_prefixed=stDisp32,
|
when_prefixed=stDisp32,
|
||||||
clobbers_flags=False,
|
clobbers_flags=False,
|
||||||
emit='''
|
emit='''
|
||||||
|
if !flags.notrap() {
|
||||||
|
sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
|
||||||
|
}
|
||||||
PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
|
PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
|
||||||
modrm_disp32(in_reg1, in_reg0, sink);
|
modrm_disp32(in_reg1, in_reg0, sink);
|
||||||
let offset: i32 = offset.into();
|
let offset: i32 = offset.into();
|
||||||
@@ -749,6 +801,9 @@ fstDisp32 = TailRecipe(
|
|||||||
'fstDisp32', Store, size=5, ins=(FPR, GPR_DEREF_SAFE), outs=(),
|
'fstDisp32', Store, size=5, ins=(FPR, GPR_DEREF_SAFE), outs=(),
|
||||||
clobbers_flags=False,
|
clobbers_flags=False,
|
||||||
emit='''
|
emit='''
|
||||||
|
if !flags.notrap() {
|
||||||
|
sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
|
||||||
|
}
|
||||||
PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
|
PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
|
||||||
modrm_disp32(in_reg1, in_reg0, sink);
|
modrm_disp32(in_reg1, in_reg0, sink);
|
||||||
let offset: i32 = offset.into();
|
let offset: i32 = offset.into();
|
||||||
@@ -756,8 +811,8 @@ fstDisp32 = TailRecipe(
|
|||||||
''')
|
''')
|
||||||
|
|
||||||
# Unary spill with SIB and 32-bit displacement.
|
# Unary spill with SIB and 32-bit displacement.
|
||||||
spSib32 = TailRecipe(
|
spillSib32 = TailRecipe(
|
||||||
'spSib32', Unary, size=6, ins=GPR, outs=StackGPR32,
|
'spillSib32', Unary, size=6, ins=GPR, outs=StackGPR32,
|
||||||
clobbers_flags=False,
|
clobbers_flags=False,
|
||||||
emit='''
|
emit='''
|
||||||
let base = stk_base(out_stk0.base);
|
let base = stk_base(out_stk0.base);
|
||||||
@@ -766,8 +821,10 @@ spSib32 = TailRecipe(
|
|||||||
sib_noindex(base, sink);
|
sib_noindex(base, sink);
|
||||||
sink.put4(out_stk0.offset as u32);
|
sink.put4(out_stk0.offset as u32);
|
||||||
''')
|
''')
|
||||||
fspSib32 = TailRecipe(
|
|
||||||
'fspSib32', Unary, size=6, ins=FPR, outs=StackFPR32,
|
# Like spillSib32, but targeting an FPR rather than a GPR.
|
||||||
|
fspillSib32 = TailRecipe(
|
||||||
|
'fspillSib32', Unary, size=6, ins=FPR, outs=StackFPR32,
|
||||||
clobbers_flags=False,
|
clobbers_flags=False,
|
||||||
emit='''
|
emit='''
|
||||||
let base = stk_base(out_stk0.base);
|
let base = stk_base(out_stk0.base);
|
||||||
@@ -778,8 +835,8 @@ fspSib32 = TailRecipe(
|
|||||||
''')
|
''')
|
||||||
|
|
||||||
# Regspill using RSP-relative addressing.
|
# Regspill using RSP-relative addressing.
|
||||||
rsp32 = TailRecipe(
|
regspill32 = TailRecipe(
|
||||||
'rsp32', RegSpill, size=6, ins=GPR, outs=(),
|
'regspill32', RegSpill, size=6, ins=GPR, outs=(),
|
||||||
clobbers_flags=False,
|
clobbers_flags=False,
|
||||||
emit='''
|
emit='''
|
||||||
let dst = StackRef::sp(dst, &func.stack_slots);
|
let dst = StackRef::sp(dst, &func.stack_slots);
|
||||||
@@ -789,8 +846,10 @@ rsp32 = TailRecipe(
|
|||||||
sib_noindex(base, sink);
|
sib_noindex(base, sink);
|
||||||
sink.put4(dst.offset as u32);
|
sink.put4(dst.offset as u32);
|
||||||
''')
|
''')
|
||||||
frsp32 = TailRecipe(
|
|
||||||
'frsp32', RegSpill, size=6, ins=FPR, outs=(),
|
# Like regspill32, but targeting an FPR rather than a GPR.
|
||||||
|
fregspill32 = TailRecipe(
|
||||||
|
'fregspill32', RegSpill, size=6, ins=FPR, outs=(),
|
||||||
clobbers_flags=False,
|
clobbers_flags=False,
|
||||||
emit='''
|
emit='''
|
||||||
let dst = StackRef::sp(dst, &func.stack_slots);
|
let dst = StackRef::sp(dst, &func.stack_slots);
|
||||||
@@ -811,6 +870,9 @@ ld = TailRecipe(
|
|||||||
instp=IsEqual(Load.offset, 0),
|
instp=IsEqual(Load.offset, 0),
|
||||||
clobbers_flags=False,
|
clobbers_flags=False,
|
||||||
emit='''
|
emit='''
|
||||||
|
if !flags.notrap() {
|
||||||
|
sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
|
||||||
|
}
|
||||||
PUT_OP(bits, rex2(in_reg0, out_reg0), sink);
|
PUT_OP(bits, rex2(in_reg0, out_reg0), sink);
|
||||||
modrm_rm(in_reg0, out_reg0, sink);
|
modrm_rm(in_reg0, out_reg0, sink);
|
||||||
''')
|
''')
|
||||||
@@ -821,6 +883,9 @@ fld = TailRecipe(
|
|||||||
instp=IsEqual(Load.offset, 0),
|
instp=IsEqual(Load.offset, 0),
|
||||||
clobbers_flags=False,
|
clobbers_flags=False,
|
||||||
emit='''
|
emit='''
|
||||||
|
if !flags.notrap() {
|
||||||
|
sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
|
||||||
|
}
|
||||||
PUT_OP(bits, rex2(in_reg0, out_reg0), sink);
|
PUT_OP(bits, rex2(in_reg0, out_reg0), sink);
|
||||||
modrm_rm(in_reg0, out_reg0, sink);
|
modrm_rm(in_reg0, out_reg0, sink);
|
||||||
''')
|
''')
|
||||||
@@ -831,6 +896,9 @@ ldDisp8 = TailRecipe(
|
|||||||
instp=IsSignedInt(Load.offset, 8),
|
instp=IsSignedInt(Load.offset, 8),
|
||||||
clobbers_flags=False,
|
clobbers_flags=False,
|
||||||
emit='''
|
emit='''
|
||||||
|
if !flags.notrap() {
|
||||||
|
sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
|
||||||
|
}
|
||||||
PUT_OP(bits, rex2(in_reg0, out_reg0), sink);
|
PUT_OP(bits, rex2(in_reg0, out_reg0), sink);
|
||||||
modrm_disp8(in_reg0, out_reg0, sink);
|
modrm_disp8(in_reg0, out_reg0, sink);
|
||||||
let offset: i32 = offset.into();
|
let offset: i32 = offset.into();
|
||||||
@@ -843,6 +911,9 @@ fldDisp8 = TailRecipe(
|
|||||||
instp=IsSignedInt(Load.offset, 8),
|
instp=IsSignedInt(Load.offset, 8),
|
||||||
clobbers_flags=False,
|
clobbers_flags=False,
|
||||||
emit='''
|
emit='''
|
||||||
|
if !flags.notrap() {
|
||||||
|
sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
|
||||||
|
}
|
||||||
PUT_OP(bits, rex2(in_reg0, out_reg0), sink);
|
PUT_OP(bits, rex2(in_reg0, out_reg0), sink);
|
||||||
modrm_disp8(in_reg0, out_reg0, sink);
|
modrm_disp8(in_reg0, out_reg0, sink);
|
||||||
let offset: i32 = offset.into();
|
let offset: i32 = offset.into();
|
||||||
@@ -855,6 +926,9 @@ ldDisp32 = TailRecipe(
|
|||||||
instp=IsSignedInt(Load.offset, 32),
|
instp=IsSignedInt(Load.offset, 32),
|
||||||
clobbers_flags=False,
|
clobbers_flags=False,
|
||||||
emit='''
|
emit='''
|
||||||
|
if !flags.notrap() {
|
||||||
|
sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
|
||||||
|
}
|
||||||
PUT_OP(bits, rex2(in_reg0, out_reg0), sink);
|
PUT_OP(bits, rex2(in_reg0, out_reg0), sink);
|
||||||
modrm_disp32(in_reg0, out_reg0, sink);
|
modrm_disp32(in_reg0, out_reg0, sink);
|
||||||
let offset: i32 = offset.into();
|
let offset: i32 = offset.into();
|
||||||
@@ -867,6 +941,9 @@ fldDisp32 = TailRecipe(
|
|||||||
instp=IsSignedInt(Load.offset, 32),
|
instp=IsSignedInt(Load.offset, 32),
|
||||||
clobbers_flags=False,
|
clobbers_flags=False,
|
||||||
emit='''
|
emit='''
|
||||||
|
if !flags.notrap() {
|
||||||
|
sink.trap(TrapCode::HeapOutOfBounds, func.srclocs[inst]);
|
||||||
|
}
|
||||||
PUT_OP(bits, rex2(in_reg0, out_reg0), sink);
|
PUT_OP(bits, rex2(in_reg0, out_reg0), sink);
|
||||||
modrm_disp32(in_reg0, out_reg0, sink);
|
modrm_disp32(in_reg0, out_reg0, sink);
|
||||||
let offset: i32 = offset.into();
|
let offset: i32 = offset.into();
|
||||||
@@ -874,8 +951,8 @@ fldDisp32 = TailRecipe(
|
|||||||
''')
|
''')
|
||||||
|
|
||||||
# Unary fill with SIB and 32-bit displacement.
|
# Unary fill with SIB and 32-bit displacement.
|
||||||
fiSib32 = TailRecipe(
|
fillSib32 = TailRecipe(
|
||||||
'fiSib32', Unary, size=6, ins=StackGPR32, outs=GPR,
|
'fillSib32', Unary, size=6, ins=StackGPR32, outs=GPR,
|
||||||
clobbers_flags=False,
|
clobbers_flags=False,
|
||||||
emit='''
|
emit='''
|
||||||
let base = stk_base(in_stk0.base);
|
let base = stk_base(in_stk0.base);
|
||||||
@@ -884,8 +961,10 @@ fiSib32 = TailRecipe(
|
|||||||
sib_noindex(base, sink);
|
sib_noindex(base, sink);
|
||||||
sink.put4(in_stk0.offset as u32);
|
sink.put4(in_stk0.offset as u32);
|
||||||
''')
|
''')
|
||||||
ffiSib32 = TailRecipe(
|
|
||||||
'ffiSib32', Unary, size=6, ins=StackFPR32, outs=FPR,
|
# Like fillSib32, but targeting an FPR rather than a GPR.
|
||||||
|
ffillSib32 = TailRecipe(
|
||||||
|
'ffillSib32', Unary, size=6, ins=StackFPR32, outs=FPR,
|
||||||
clobbers_flags=False,
|
clobbers_flags=False,
|
||||||
emit='''
|
emit='''
|
||||||
let base = stk_base(in_stk0.base);
|
let base = stk_base(in_stk0.base);
|
||||||
@@ -896,8 +975,8 @@ ffiSib32 = TailRecipe(
|
|||||||
''')
|
''')
|
||||||
|
|
||||||
# Regfill with RSP-relative 32-bit displacement.
|
# Regfill with RSP-relative 32-bit displacement.
|
||||||
rfi32 = TailRecipe(
|
regfill32 = TailRecipe(
|
||||||
'rfi32', RegFill, size=6, ins=StackGPR32, outs=(),
|
'regfill32', RegFill, size=6, ins=StackGPR32, outs=(),
|
||||||
clobbers_flags=False,
|
clobbers_flags=False,
|
||||||
emit='''
|
emit='''
|
||||||
let src = StackRef::sp(src, &func.stack_slots);
|
let src = StackRef::sp(src, &func.stack_slots);
|
||||||
@@ -907,8 +986,10 @@ rfi32 = TailRecipe(
|
|||||||
sib_noindex(base, sink);
|
sib_noindex(base, sink);
|
||||||
sink.put4(src.offset as u32);
|
sink.put4(src.offset as u32);
|
||||||
''')
|
''')
|
||||||
frfi32 = TailRecipe(
|
|
||||||
'frfi32', RegFill, size=6, ins=StackFPR32, outs=(),
|
# Like regfill32, but targeting an FPR rather than a GPR.
|
||||||
|
fregfill32 = TailRecipe(
|
||||||
|
'fregfill32', RegFill, size=6, ins=StackFPR32, outs=(),
|
||||||
clobbers_flags=False,
|
clobbers_flags=False,
|
||||||
emit='''
|
emit='''
|
||||||
let src = StackRef::sp(src, &func.stack_slots);
|
let src = StackRef::sp(src, &func.stack_slots);
|
||||||
@@ -977,7 +1058,7 @@ jmpd = TailRecipe(
|
|||||||
''')
|
''')
|
||||||
|
|
||||||
brib = TailRecipe(
|
brib = TailRecipe(
|
||||||
'brib', BranchInt, size=1, ins=FLAG.eflags, outs=(),
|
'brib', BranchInt, size=1, ins=FLAG.rflags, outs=(),
|
||||||
branch_range=8,
|
branch_range=8,
|
||||||
clobbers_flags=False,
|
clobbers_flags=False,
|
||||||
emit='''
|
emit='''
|
||||||
@@ -986,7 +1067,7 @@ brib = TailRecipe(
|
|||||||
''')
|
''')
|
||||||
|
|
||||||
brid = TailRecipe(
|
brid = TailRecipe(
|
||||||
'brid', BranchInt, size=4, ins=FLAG.eflags, outs=(),
|
'brid', BranchInt, size=4, ins=FLAG.rflags, outs=(),
|
||||||
branch_range=32,
|
branch_range=32,
|
||||||
clobbers_flags=False,
|
clobbers_flags=False,
|
||||||
emit='''
|
emit='''
|
||||||
@@ -995,7 +1076,7 @@ brid = TailRecipe(
|
|||||||
''')
|
''')
|
||||||
|
|
||||||
brfb = TailRecipe(
|
brfb = TailRecipe(
|
||||||
'brfb', BranchFloat, size=1, ins=FLAG.eflags, outs=(),
|
'brfb', BranchFloat, size=1, ins=FLAG.rflags, outs=(),
|
||||||
branch_range=8,
|
branch_range=8,
|
||||||
clobbers_flags=False,
|
clobbers_flags=False,
|
||||||
instp=floatccs(BranchFloat),
|
instp=floatccs(BranchFloat),
|
||||||
@@ -1005,7 +1086,7 @@ brfb = TailRecipe(
|
|||||||
''')
|
''')
|
||||||
|
|
||||||
brfd = TailRecipe(
|
brfd = TailRecipe(
|
||||||
'brfd', BranchFloat, size=4, ins=FLAG.eflags, outs=(),
|
'brfd', BranchFloat, size=4, ins=FLAG.rflags, outs=(),
|
||||||
branch_range=32,
|
branch_range=32,
|
||||||
clobbers_flags=False,
|
clobbers_flags=False,
|
||||||
instp=floatccs(BranchFloat),
|
instp=floatccs(BranchFloat),
|
||||||
@@ -1025,7 +1106,7 @@ brfd = TailRecipe(
|
|||||||
#
|
#
|
||||||
|
|
||||||
seti = TailRecipe(
|
seti = TailRecipe(
|
||||||
'seti', IntCond, size=1, ins=FLAG.eflags, outs=GPR,
|
'seti', IntCond, size=1, ins=FLAG.rflags, outs=GPR,
|
||||||
requires_prefix=True,
|
requires_prefix=True,
|
||||||
clobbers_flags=False,
|
clobbers_flags=False,
|
||||||
emit='''
|
emit='''
|
||||||
@@ -1033,7 +1114,7 @@ seti = TailRecipe(
|
|||||||
modrm_r_bits(out_reg0, bits, sink);
|
modrm_r_bits(out_reg0, bits, sink);
|
||||||
''')
|
''')
|
||||||
seti_abcd = TailRecipe(
|
seti_abcd = TailRecipe(
|
||||||
'seti_abcd', IntCond, size=1, ins=FLAG.eflags, outs=ABCD,
|
'seti_abcd', IntCond, size=1, ins=FLAG.rflags, outs=ABCD,
|
||||||
when_prefixed=seti,
|
when_prefixed=seti,
|
||||||
clobbers_flags=False,
|
clobbers_flags=False,
|
||||||
emit='''
|
emit='''
|
||||||
@@ -1042,7 +1123,7 @@ seti_abcd = TailRecipe(
|
|||||||
''')
|
''')
|
||||||
|
|
||||||
setf = TailRecipe(
|
setf = TailRecipe(
|
||||||
'setf', FloatCond, size=1, ins=FLAG.eflags, outs=GPR,
|
'setf', FloatCond, size=1, ins=FLAG.rflags, outs=GPR,
|
||||||
requires_prefix=True,
|
requires_prefix=True,
|
||||||
clobbers_flags=False,
|
clobbers_flags=False,
|
||||||
emit='''
|
emit='''
|
||||||
@@ -1050,7 +1131,7 @@ setf = TailRecipe(
|
|||||||
modrm_r_bits(out_reg0, bits, sink);
|
modrm_r_bits(out_reg0, bits, sink);
|
||||||
''')
|
''')
|
||||||
setf_abcd = TailRecipe(
|
setf_abcd = TailRecipe(
|
||||||
'setf_abcd', FloatCond, size=1, ins=FLAG.eflags, outs=ABCD,
|
'setf_abcd', FloatCond, size=1, ins=FLAG.rflags, outs=ABCD,
|
||||||
when_prefixed=setf,
|
when_prefixed=setf,
|
||||||
clobbers_flags=False,
|
clobbers_flags=False,
|
||||||
emit='''
|
emit='''
|
||||||
@@ -1064,7 +1145,7 @@ setf_abcd = TailRecipe(
|
|||||||
# 1 byte, modrm(r,r), is after the opcode
|
# 1 byte, modrm(r,r), is after the opcode
|
||||||
#
|
#
|
||||||
cmov = TailRecipe(
|
cmov = TailRecipe(
|
||||||
'cmov', IntSelect, size=1, ins=(FLAG.eflags, GPR, GPR), outs=2,
|
'cmov', IntSelect, size=1, ins=(FLAG.rflags, GPR, GPR), outs=2,
|
||||||
requires_prefix=False,
|
requires_prefix=False,
|
||||||
clobbers_flags=False,
|
clobbers_flags=False,
|
||||||
emit='''
|
emit='''
|
||||||
@@ -1076,7 +1157,7 @@ cmov = TailRecipe(
|
|||||||
# Bit scan forwards and reverse
|
# Bit scan forwards and reverse
|
||||||
#
|
#
|
||||||
bsf_and_bsr = TailRecipe(
|
bsf_and_bsr = TailRecipe(
|
||||||
'bsf_and_bsr', Unary, size=1, ins=GPR, outs=(GPR, FLAG.eflags),
|
'bsf_and_bsr', Unary, size=1, ins=GPR, outs=(GPR, FLAG.rflags),
|
||||||
requires_prefix=False,
|
requires_prefix=False,
|
||||||
clobbers_flags=True,
|
clobbers_flags=True,
|
||||||
emit='''
|
emit='''
|
||||||
@@ -1090,7 +1171,7 @@ bsf_and_bsr = TailRecipe(
|
|||||||
|
|
||||||
# XX /r, MR form. Compare two GPR registers and set flags.
|
# XX /r, MR form. Compare two GPR registers and set flags.
|
||||||
rcmp = TailRecipe(
|
rcmp = TailRecipe(
|
||||||
'rcmp', Binary, size=1, ins=(GPR, GPR), outs=FLAG.eflags,
|
'rcmp', Binary, size=1, ins=(GPR, GPR), outs=FLAG.rflags,
|
||||||
emit='''
|
emit='''
|
||||||
PUT_OP(bits, rex2(in_reg0, in_reg1), sink);
|
PUT_OP(bits, rex2(in_reg0, in_reg1), sink);
|
||||||
modrm_rr(in_reg0, in_reg1, sink);
|
modrm_rr(in_reg0, in_reg1, sink);
|
||||||
@@ -1098,7 +1179,7 @@ rcmp = TailRecipe(
|
|||||||
|
|
||||||
# XX /r, RM form. Compare two FPR registers and set flags.
|
# XX /r, RM form. Compare two FPR registers and set flags.
|
||||||
fcmp = TailRecipe(
|
fcmp = TailRecipe(
|
||||||
'fcmp', Binary, size=1, ins=(FPR, FPR), outs=FLAG.eflags,
|
'fcmp', Binary, size=1, ins=(FPR, FPR), outs=FLAG.rflags,
|
||||||
emit='''
|
emit='''
|
||||||
PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
|
PUT_OP(bits, rex2(in_reg1, in_reg0), sink);
|
||||||
modrm_rr(in_reg1, in_reg0, sink);
|
modrm_rr(in_reg1, in_reg0, sink);
|
||||||
@@ -1106,7 +1187,7 @@ fcmp = TailRecipe(
|
|||||||
|
|
||||||
# XX /n, MI form with imm8.
|
# XX /n, MI form with imm8.
|
||||||
rcmpib = TailRecipe(
|
rcmpib = TailRecipe(
|
||||||
'rcmpib', BinaryImm, size=2, ins=GPR, outs=FLAG.eflags,
|
'rcmpib', BinaryImm, size=2, ins=GPR, outs=FLAG.rflags,
|
||||||
instp=IsSignedInt(BinaryImm.imm, 8),
|
instp=IsSignedInt(BinaryImm.imm, 8),
|
||||||
emit='''
|
emit='''
|
||||||
PUT_OP(bits, rex1(in_reg0), sink);
|
PUT_OP(bits, rex1(in_reg0), sink);
|
||||||
@@ -1117,7 +1198,7 @@ rcmpib = TailRecipe(
|
|||||||
|
|
||||||
# XX /n, MI form with imm32.
|
# XX /n, MI form with imm32.
|
||||||
rcmpid = TailRecipe(
|
rcmpid = TailRecipe(
|
||||||
'rcmpid', BinaryImm, size=5, ins=GPR, outs=FLAG.eflags,
|
'rcmpid', BinaryImm, size=5, ins=GPR, outs=FLAG.rflags,
|
||||||
instp=IsSignedInt(BinaryImm.imm, 32),
|
instp=IsSignedInt(BinaryImm.imm, 32),
|
||||||
emit='''
|
emit='''
|
||||||
PUT_OP(bits, rex1(in_reg0), sink);
|
PUT_OP(bits, rex1(in_reg0), sink);
|
||||||
@@ -1128,7 +1209,7 @@ rcmpid = TailRecipe(
|
|||||||
|
|
||||||
# Same as rcmp, but second operand is the stack pointer.
|
# Same as rcmp, but second operand is the stack pointer.
|
||||||
rcmp_sp = TailRecipe(
|
rcmp_sp = TailRecipe(
|
||||||
'rcmp_sp', Unary, size=1, ins=GPR, outs=FLAG.eflags,
|
'rcmp_sp', Unary, size=1, ins=GPR, outs=FLAG.rflags,
|
||||||
emit='''
|
emit='''
|
||||||
PUT_OP(bits, rex2(in_reg0, RU::rsp.into()), sink);
|
PUT_OP(bits, rex2(in_reg0, RU::rsp.into()), sink);
|
||||||
modrm_rr(in_reg0, RU::rsp.into(), sink);
|
modrm_rr(in_reg0, RU::rsp.into(), sink);
|
||||||
@@ -1289,12 +1370,67 @@ icscc = TailRecipe(
|
|||||||
modrm_rr(out_reg0, 0, sink);
|
modrm_rr(out_reg0, 0, sink);
|
||||||
''')
|
''')
|
||||||
|
|
||||||
|
icsccib = TailRecipe(
|
||||||
|
'icsccib', IntCompareImm, size=2 + 3, ins=GPR, outs=ABCD,
|
||||||
|
instp=IsSignedInt(IntCompareImm.imm, 8),
|
||||||
|
emit='''
|
||||||
|
// Comparison instruction.
|
||||||
|
PUT_OP(bits, rex1(in_reg0), sink);
|
||||||
|
modrm_r_bits(in_reg0, bits, sink);
|
||||||
|
let imm: i64 = imm.into();
|
||||||
|
sink.put1(imm as u8);
|
||||||
|
// `setCC` instruction, no REX.
|
||||||
|
use ir::condcodes::IntCC::*;
|
||||||
|
let setcc = match cond {
|
||||||
|
Equal => 0x94,
|
||||||
|
NotEqual => 0x95,
|
||||||
|
SignedLessThan => 0x9c,
|
||||||
|
SignedGreaterThanOrEqual => 0x9d,
|
||||||
|
SignedGreaterThan => 0x9f,
|
||||||
|
SignedLessThanOrEqual => 0x9e,
|
||||||
|
UnsignedLessThan => 0x92,
|
||||||
|
UnsignedGreaterThanOrEqual => 0x93,
|
||||||
|
UnsignedGreaterThan => 0x97,
|
||||||
|
UnsignedLessThanOrEqual => 0x96,
|
||||||
|
};
|
||||||
|
sink.put1(0x0f);
|
||||||
|
sink.put1(setcc);
|
||||||
|
modrm_rr(out_reg0, 0, sink);
|
||||||
|
''')
|
||||||
|
|
||||||
|
icsccid = TailRecipe(
|
||||||
|
'icsccid', IntCompareImm, size=5 + 3, ins=GPR, outs=ABCD,
|
||||||
|
instp=IsSignedInt(IntCompareImm.imm, 32),
|
||||||
|
emit='''
|
||||||
|
// Comparison instruction.
|
||||||
|
PUT_OP(bits, rex1(in_reg0), sink);
|
||||||
|
modrm_r_bits(in_reg0, bits, sink);
|
||||||
|
let imm: i64 = imm.into();
|
||||||
|
sink.put4(imm as u32);
|
||||||
|
// `setCC` instruction, no REX.
|
||||||
|
use ir::condcodes::IntCC::*;
|
||||||
|
let setcc = match cond {
|
||||||
|
Equal => 0x94,
|
||||||
|
NotEqual => 0x95,
|
||||||
|
SignedLessThan => 0x9c,
|
||||||
|
SignedGreaterThanOrEqual => 0x9d,
|
||||||
|
SignedGreaterThan => 0x9f,
|
||||||
|
SignedLessThanOrEqual => 0x9e,
|
||||||
|
UnsignedLessThan => 0x92,
|
||||||
|
UnsignedGreaterThanOrEqual => 0x93,
|
||||||
|
UnsignedGreaterThan => 0x97,
|
||||||
|
UnsignedLessThanOrEqual => 0x96,
|
||||||
|
};
|
||||||
|
sink.put1(0x0f);
|
||||||
|
sink.put1(setcc);
|
||||||
|
modrm_rr(out_reg0, 0, sink);
|
||||||
|
''')
|
||||||
|
|
||||||
# Make a FloatCompare instruction predicate with the supported condition codes.
|
# Make a FloatCompare instruction predicate with the supported condition codes.
|
||||||
|
|
||||||
# Same thing for floating point.
|
# Same thing for floating point.
|
||||||
#
|
#
|
||||||
# The ucomiss/ucomisd instructions set the EFLAGS bits CF/PF/CF like this:
|
# The ucomiss/ucomisd instructions set the FLAGS bits CF/PF/CF like this:
|
||||||
#
|
#
|
||||||
# ZPC OSA
|
# ZPC OSA
|
||||||
# UN 111 000
|
# UN 111 000
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ FlagRegs = RegBank(
|
|||||||
'Flag registers',
|
'Flag registers',
|
||||||
units=1,
|
units=1,
|
||||||
pressure_tracking=False,
|
pressure_tracking=False,
|
||||||
names=['eflags'])
|
names=['rflags'])
|
||||||
|
|
||||||
GPR = RegClass(IntRegs)
|
GPR = RegClass(IntRegs)
|
||||||
# Certain types of deref encodings cannot be used with all registers.
|
# Certain types of deref encodings cannot be used with all registers.
|
||||||
|
|||||||
@@ -8,9 +8,10 @@ source code.
|
|||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
from collections import OrderedDict
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from typing import Any, List # noqa
|
from typing import Any, List, Set, Tuple # noqa
|
||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -146,6 +147,52 @@ class Formatter(object):
|
|||||||
for l in parse_multiline(s):
|
for l in parse_multiline(s):
|
||||||
self.line('/// ' + l if l else '///')
|
self.line('/// ' + l if l else '///')
|
||||||
|
|
||||||
|
def match(self, m):
|
||||||
|
# type: (Match) -> None
|
||||||
|
"""
|
||||||
|
Add a match expression.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
>>> f = Formatter()
|
||||||
|
>>> m = Match('x')
|
||||||
|
>>> m.arm('Orange', ['a', 'b'], 'some body')
|
||||||
|
>>> m.arm('Yellow', ['a', 'b'], 'some body')
|
||||||
|
>>> m.arm('Green', ['a', 'b'], 'different body')
|
||||||
|
>>> m.arm('Blue', ['x', 'y'], 'some body')
|
||||||
|
>>> f.match(m)
|
||||||
|
>>> f.writelines()
|
||||||
|
match x {
|
||||||
|
Orange { a, b } |
|
||||||
|
Yellow { a, b } => {
|
||||||
|
some body
|
||||||
|
}
|
||||||
|
Green { a, b } => {
|
||||||
|
different body
|
||||||
|
}
|
||||||
|
Blue { x, y } => {
|
||||||
|
some body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"""
|
||||||
|
with self.indented('match {} {{'.format(m.expr), '}'):
|
||||||
|
for (fields, body), names in m.arms.items():
|
||||||
|
with self.indented('', '}'):
|
||||||
|
names_left = len(names)
|
||||||
|
for name in names.keys():
|
||||||
|
fields_str = ', '.join(fields)
|
||||||
|
if len(fields) != 0:
|
||||||
|
fields_str = '{{ {} }} '.format(fields_str)
|
||||||
|
names_left -= 1
|
||||||
|
if names_left > 0:
|
||||||
|
suffix = '|'
|
||||||
|
else:
|
||||||
|
suffix = '=> {'
|
||||||
|
self.outdented_line(name + ' ' + fields_str + suffix)
|
||||||
|
if names_left == 0:
|
||||||
|
self.multi_line(body)
|
||||||
|
|
||||||
|
|
||||||
def _indent(s):
|
def _indent(s):
|
||||||
# type: (str) -> int
|
# type: (str) -> int
|
||||||
@@ -195,3 +242,36 @@ def parse_multiline(s):
|
|||||||
while trimmed and not trimmed[0]:
|
while trimmed and not trimmed[0]:
|
||||||
trimmed.pop(0)
|
trimmed.pop(0)
|
||||||
return trimmed
|
return trimmed
|
||||||
|
|
||||||
|
|
||||||
|
class Match(object):
|
||||||
|
"""
|
||||||
|
Match formatting class.
|
||||||
|
|
||||||
|
Match objects collect all the information needed to emit a Rust `match`
|
||||||
|
expression, automatically deduplicating overlapping identical arms.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
>>> m = Match('x')
|
||||||
|
>>> m.arm('Orange', ['a', 'b'], 'some body')
|
||||||
|
>>> m.arm('Yellow', ['a', 'b'], 'some body')
|
||||||
|
>>> m.arm('Green', ['a', 'b'], 'different body')
|
||||||
|
>>> m.arm('Blue', ['x', 'y'], 'some body')
|
||||||
|
>>> assert(len(m.arms) == 3)
|
||||||
|
|
||||||
|
Note that this class is ignorant of Rust types, and considers two fields
|
||||||
|
with the same name to be equivalent.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, expr):
|
||||||
|
# type: (str) -> None
|
||||||
|
self.expr = expr
|
||||||
|
self.arms = OrderedDict() # type: OrderedDict[Tuple[Tuple[str, ...], str], OrderedDict[str, None]] # noqa
|
||||||
|
|
||||||
|
def arm(self, name, fields, body):
|
||||||
|
# type: (str, List[str], str) -> None
|
||||||
|
key = (tuple(fields), body)
|
||||||
|
if key not in self.arms:
|
||||||
|
self.arms[key] = OrderedDict()
|
||||||
|
self.arms[key][name] = None
|
||||||
|
|||||||
@@ -148,9 +148,9 @@ class TestRuntimeChecks(TestCase):
|
|||||||
self.v5 << vselect(self.v1, self.v3, self.v4),
|
self.v5 << vselect(self.v1, self.v3, self.v4),
|
||||||
)
|
)
|
||||||
x = XForm(r, r)
|
x = XForm(r, r)
|
||||||
tv2_exp = 'Some({}).map(|t: Type| -> t.as_bool())'\
|
tv2_exp = 'Some({}).map(|t: ir::Type| t.as_bool())'\
|
||||||
.format(self.v2.get_typevar().name)
|
.format(self.v2.get_typevar().name)
|
||||||
tv3_exp = 'Some({}).map(|t: Type| -> t.as_bool())'\
|
tv3_exp = 'Some({}).map(|t: ir::Type| t.as_bool())'\
|
||||||
.format(self.v3.get_typevar().name)
|
.format(self.v3.get_typevar().name)
|
||||||
|
|
||||||
self.check_yo_check(
|
self.check_yo_check(
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
//! This module provides functions and data structures that are useful for implementing the
|
//! This module provides functions and data structures that are useful for implementing the
|
||||||
//! `TargetIsa::legalize_signature()` method.
|
//! `TargetIsa::legalize_signature()` method.
|
||||||
|
|
||||||
use ir::{ArgumentLoc, AbiParam, ArgumentExtension, Type};
|
use ir::{AbiParam, ArgumentExtension, ArgumentLoc, Type};
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
|
|
||||||
@@ -186,8 +186,8 @@ pub fn legalize_abi_value(have: Type, arg: &AbiParam) -> ValueConversion {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use ir::types;
|
|
||||||
use ir::AbiParam;
|
use ir::AbiParam;
|
||||||
|
use ir::types;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn legalize() {
|
fn legalize() {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
//! Forest of maps.
|
//! Forest of maps.
|
||||||
|
|
||||||
|
use super::{Comparator, Forest, Node, NodeData, NodePool, Path, INNER_SIZE};
|
||||||
use packed_option::PackedOption;
|
use packed_option::PackedOption;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use super::{INNER_SIZE, Comparator, Forest, NodePool, Node, NodeData, Path};
|
|
||||||
|
|
||||||
/// Tag type defining forest types for a map.
|
/// Tag type defining forest types for a map.
|
||||||
struct MapTypes<K, V, C>(PhantomData<(K, V, C)>);
|
struct MapTypes<K, V, C>(PhantomData<(K, V, C)>);
|
||||||
@@ -424,10 +424,10 @@ where
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
use super::super::NodeData;
|
||||||
|
use super::*;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
use super::*;
|
|
||||||
use super::super::NodeData;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn node_size() {
|
fn node_size() {
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ mod path;
|
|||||||
mod pool;
|
mod pool;
|
||||||
mod set;
|
mod set;
|
||||||
|
|
||||||
pub use self::map::{MapForest, Map, MapCursor, MapIter};
|
pub use self::map::{Map, MapCursor, MapForest, MapIter};
|
||||||
pub use self::set::{SetForest, Set, SetCursor, SetIter};
|
pub use self::set::{Set, SetCursor, SetForest, SetIter};
|
||||||
|
|
||||||
use self::node::NodeData;
|
use self::node::NodeData;
|
||||||
use self::path::Path;
|
use self::path::Path;
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
//! B+-tree nodes.
|
//! B+-tree nodes.
|
||||||
|
|
||||||
|
use super::{slice_insert, slice_shift, Forest, Node, SetValue, INNER_SIZE};
|
||||||
use std::borrow::{Borrow, BorrowMut};
|
use std::borrow::{Borrow, BorrowMut};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use super::{Forest, Node, INNER_SIZE, SetValue, slice_insert, slice_shift};
|
|
||||||
|
|
||||||
/// B+-tree node.
|
/// B+-tree node.
|
||||||
///
|
///
|
||||||
@@ -579,9 +579,9 @@ where
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
use super::*;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::string::ToString;
|
use std::string::ToString;
|
||||||
use super::*;
|
|
||||||
|
|
||||||
// Forest impl for a set implementation.
|
// Forest impl for a set implementation.
|
||||||
struct TF();
|
struct TF();
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
//! A path from the root of a B+-tree to a leaf node.
|
//! A path from the root of a B+-tree to a leaf node.
|
||||||
|
|
||||||
|
use super::node::Removed;
|
||||||
|
use super::{slice_insert, slice_shift, Comparator, Forest, Node, NodeData, NodePool, MAX_PATH};
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use super::{Forest, Node, NodeData, NodePool, MAX_PATH, Comparator, slice_insert, slice_shift};
|
|
||||||
use super::node::Removed;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
@@ -55,8 +55,8 @@ impl<F: Forest> Path<F> {
|
|||||||
for level in 0.. {
|
for level in 0.. {
|
||||||
self.size = level + 1;
|
self.size = level + 1;
|
||||||
self.node[level] = node;
|
self.node[level] = node;
|
||||||
match &pool[node] {
|
match pool[node] {
|
||||||
&NodeData::Inner { size, keys, tree } => {
|
NodeData::Inner { size, keys, tree } => {
|
||||||
// Invariant: `tree[i]` contains keys smaller than
|
// Invariant: `tree[i]` contains keys smaller than
|
||||||
// `keys[i]`, greater or equal to `keys[i-1]`.
|
// `keys[i]`, greater or equal to `keys[i-1]`.
|
||||||
let i = match comp.search(key, &keys[0..size.into()]) {
|
let i = match comp.search(key, &keys[0..size.into()]) {
|
||||||
@@ -68,7 +68,7 @@ impl<F: Forest> Path<F> {
|
|||||||
self.entry[level] = i as u8;
|
self.entry[level] = i as u8;
|
||||||
node = tree[i];
|
node = tree[i];
|
||||||
}
|
}
|
||||||
&NodeData::Leaf { size, keys, vals } => {
|
NodeData::Leaf { size, keys, vals } => {
|
||||||
// For a leaf we want either the found key or an insert position.
|
// For a leaf we want either the found key or an insert position.
|
||||||
return match comp.search(key, &keys.borrow()[0..size.into()]) {
|
return match comp.search(key, &keys.borrow()[0..size.into()]) {
|
||||||
Ok(i) => {
|
Ok(i) => {
|
||||||
@@ -81,7 +81,7 @@ impl<F: Forest> Path<F> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
&NodeData::Free { .. } => panic!("Free {} reached from {}", node, root),
|
NodeData::Free { .. } => panic!("Free {} reached from {}", node, root),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unreachable!();
|
unreachable!();
|
||||||
@@ -94,10 +94,10 @@ impl<F: Forest> Path<F> {
|
|||||||
self.size = level + 1;
|
self.size = level + 1;
|
||||||
self.node[level] = node;
|
self.node[level] = node;
|
||||||
self.entry[level] = 0;
|
self.entry[level] = 0;
|
||||||
match &pool[node] {
|
match pool[node] {
|
||||||
&NodeData::Inner { tree, .. } => node = tree[0],
|
NodeData::Inner { tree, .. } => node = tree[0],
|
||||||
&NodeData::Leaf { keys, vals, .. } => return (keys.borrow()[0], vals.borrow()[0]),
|
NodeData::Leaf { keys, vals, .. } => return (keys.borrow()[0], vals.borrow()[0]),
|
||||||
&NodeData::Free { .. } => panic!("Free {} reached from {}", node, root),
|
NodeData::Free { .. } => panic!("Free {} reached from {}", node, root),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unreachable!();
|
unreachable!();
|
||||||
@@ -205,17 +205,17 @@ impl<F: Forest> Path<F> {
|
|||||||
let mut node = root;
|
let mut node = root;
|
||||||
for l in level.. {
|
for l in level.. {
|
||||||
self.node[l] = node;
|
self.node[l] = node;
|
||||||
match &pool[node] {
|
match pool[node] {
|
||||||
&NodeData::Inner { size, ref tree, .. } => {
|
NodeData::Inner { size, ref tree, .. } => {
|
||||||
self.entry[l] = size;
|
self.entry[l] = size;
|
||||||
node = tree[usize::from(size)];
|
node = tree[usize::from(size)];
|
||||||
}
|
}
|
||||||
&NodeData::Leaf { size, .. } => {
|
NodeData::Leaf { size, .. } => {
|
||||||
self.entry[l] = size - 1;
|
self.entry[l] = size - 1;
|
||||||
self.size = l + 1;
|
self.size = l + 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
&NodeData::Free { .. } => panic!("Free {} reached from {}", node, root),
|
NodeData::Free { .. } => panic!("Free {} reached from {}", node, root),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
node
|
node
|
||||||
@@ -405,8 +405,8 @@ impl<F: Forest> Path<F> {
|
|||||||
let crit_key = pool[self.leaf_node()].leaf_crit_key();
|
let crit_key = pool[self.leaf_node()].leaf_crit_key();
|
||||||
let crit_node = self.node[crit_level];
|
let crit_node = self.node[crit_level];
|
||||||
|
|
||||||
match &mut pool[crit_node] {
|
match pool[crit_node] {
|
||||||
&mut NodeData::Inner { size, ref mut keys, .. } => {
|
NodeData::Inner { size, ref mut keys, .. } => {
|
||||||
debug_assert!(crit_kidx < size);
|
debug_assert!(crit_kidx < size);
|
||||||
keys[usize::from(crit_kidx)] = crit_key;
|
keys[usize::from(crit_kidx)] = crit_key;
|
||||||
}
|
}
|
||||||
@@ -414,7 +414,6 @@ impl<F: Forest> Path<F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Given that the current leaf node is in an unhealthy (underflowed or even empty) status,
|
/// Given that the current leaf node is in an unhealthy (underflowed or even empty) status,
|
||||||
/// balance it with sibling nodes.
|
/// balance it with sibling nodes.
|
||||||
///
|
///
|
||||||
@@ -437,7 +436,7 @@ impl<F: Forest> Path<F> {
|
|||||||
|
|
||||||
// Discard the root node if it has shrunk to a single sub-tree.
|
// Discard the root node if it has shrunk to a single sub-tree.
|
||||||
let mut ns = 0;
|
let mut ns = 0;
|
||||||
while let &NodeData::Inner { size: 0, ref tree, .. } = &pool[self.node[ns]] {
|
while let NodeData::Inner { size: 0, ref tree, .. } = pool[self.node[ns]] {
|
||||||
ns += 1;
|
ns += 1;
|
||||||
self.node[ns] = tree[0];
|
self.node[ns] = tree[0];
|
||||||
}
|
}
|
||||||
@@ -529,14 +528,12 @@ impl<F: Forest> Path<F> {
|
|||||||
// current entry[level] was one off the end of the node, it will now point at a proper
|
// current entry[level] was one off the end of the node, it will now point at a proper
|
||||||
// entry.
|
// entry.
|
||||||
debug_assert!(usize::from(self.entry[level]) < pool[self.node[level]].entries());
|
debug_assert!(usize::from(self.entry[level]) < pool[self.node[level]].entries());
|
||||||
} else {
|
} else if usize::from(self.entry[level]) >= pool[self.node[level]].entries() {
|
||||||
// There's no right sibling at this level, so the node can't be rebalanced.
|
// There's no right sibling at this level, so the node can't be rebalanced.
|
||||||
// Check if we are in an off-the-end position.
|
// Check if we are in an off-the-end position.
|
||||||
if usize::from(self.entry[level]) >= pool[self.node[level]].entries() {
|
|
||||||
self.size = 0;
|
self.size = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// The current node at `level` has become empty.
|
/// The current node at `level` has become empty.
|
||||||
///
|
///
|
||||||
@@ -581,8 +578,8 @@ impl<F: Forest> Path<F> {
|
|||||||
///
|
///
|
||||||
/// Returns `None` if the current node is a right-most node so no right sibling exists.
|
/// Returns `None` if the current node is a right-most node so no right sibling exists.
|
||||||
fn right_sibling_branch_level(&self, level: usize, pool: &NodePool<F>) -> Option<usize> {
|
fn right_sibling_branch_level(&self, level: usize, pool: &NodePool<F>) -> Option<usize> {
|
||||||
(0..level).rposition(|l| match &pool[self.node[l]] {
|
(0..level).rposition(|l| match pool[self.node[l]] {
|
||||||
&NodeData::Inner { size, .. } => self.entry[l] < size,
|
NodeData::Inner { size, .. } => self.entry[l] < size,
|
||||||
_ => panic!("Expected inner node"),
|
_ => panic!("Expected inner node"),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -622,8 +619,8 @@ impl<F: Forest> Path<F> {
|
|||||||
let bl = self.right_sibling_branch_level(level, pool).expect(
|
let bl = self.right_sibling_branch_level(level, pool).expect(
|
||||||
"No right sibling exists",
|
"No right sibling exists",
|
||||||
);
|
);
|
||||||
match &mut pool[self.node[bl]] {
|
match pool[self.node[bl]] {
|
||||||
&mut NodeData::Inner { ref mut keys, .. } => {
|
NodeData::Inner { ref mut keys, .. } => {
|
||||||
keys[usize::from(self.entry[bl])] = crit_key;
|
keys[usize::from(self.entry[bl])] = crit_key;
|
||||||
}
|
}
|
||||||
_ => panic!("Expected inner node"),
|
_ => panic!("Expected inner node"),
|
||||||
@@ -647,8 +644,8 @@ impl<F: Forest> Path<F> {
|
|||||||
/// Check the internal consistency of this path.
|
/// Check the internal consistency of this path.
|
||||||
pub fn verify(&self, pool: &NodePool<F>) {
|
pub fn verify(&self, pool: &NodePool<F>) {
|
||||||
for level in 0..self.size {
|
for level in 0..self.size {
|
||||||
match &pool[self.node[level]] {
|
match pool[self.node[level]] {
|
||||||
&NodeData::Inner { size, tree, .. } => {
|
NodeData::Inner { size, tree, .. } => {
|
||||||
assert!(
|
assert!(
|
||||||
level < self.size - 1,
|
level < self.size - 1,
|
||||||
"Expected leaf node at level {}",
|
"Expected leaf node at level {}",
|
||||||
@@ -668,7 +665,7 @@ impl<F: Forest> Path<F> {
|
|||||||
level
|
level
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
&NodeData::Leaf { size, .. } => {
|
NodeData::Leaf { size, .. } => {
|
||||||
assert_eq!(level, self.size - 1, "Expected inner node");
|
assert_eq!(level, self.size - 1, "Expected inner node");
|
||||||
assert!(
|
assert!(
|
||||||
self.entry[level] <= size,
|
self.entry[level] <= size,
|
||||||
@@ -677,7 +674,7 @@ impl<F: Forest> Path<F> {
|
|||||||
size,
|
size,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
&NodeData::Free { .. } => {
|
NodeData::Free { .. } => {
|
||||||
panic!("Free {} in path", self.node[level]);
|
panic!("Free {} in path", self.node[level]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -702,9 +699,9 @@ impl<F: Forest> fmt::Display for Path<F> {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use std::cmp::Ordering;
|
use super::super::{Forest, NodeData, NodePool};
|
||||||
use super::*;
|
use super::*;
|
||||||
use super::super::{Forest, NodePool, NodeData};
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
struct TC();
|
struct TC();
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
//! B+-tree node pool.
|
//! B+-tree node pool.
|
||||||
|
|
||||||
|
use super::{Forest, Node, NodeData};
|
||||||
use entity::PrimaryMap;
|
use entity::PrimaryMap;
|
||||||
use std::ops::{Index, IndexMut};
|
use std::ops::{Index, IndexMut};
|
||||||
use super::{Forest, Node, NodeData};
|
|
||||||
|
|
||||||
/// A pool of nodes, including a free list.
|
/// A pool of nodes, including a free list.
|
||||||
pub(super) struct NodePool<F: Forest> {
|
pub(super) struct NodePool<F: Forest> {
|
||||||
@@ -57,6 +57,7 @@ impl<F: Forest> NodePool<F> {
|
|||||||
pub fn free_tree(&mut self, node: Node) {
|
pub fn free_tree(&mut self, node: Node) {
|
||||||
if let NodeData::Inner { size, tree, .. } = self[node] {
|
if let NodeData::Inner { size, tree, .. } = self[node] {
|
||||||
// Note that we have to capture `tree` by value to avoid borrow checker trouble.
|
// Note that we have to capture `tree` by value to avoid borrow checker trouble.
|
||||||
|
#[cfg_attr(feature = "cargo-clippy", allow(needless_range_loop))]
|
||||||
for i in 0..usize::from(size + 1) {
|
for i in 0..usize::from(size + 1) {
|
||||||
// Recursively free sub-trees. This recursion can never be deeper than `MAX_PATH`,
|
// Recursively free sub-trees. This recursion can never be deeper than `MAX_PATH`,
|
||||||
// and since most trees have less than a handful of nodes, it is worthwhile to
|
// and since most trees have less than a handful of nodes, it is worthwhile to
|
||||||
@@ -76,11 +77,11 @@ impl<F: Forest> NodePool<F> {
|
|||||||
NodeData<F>: ::std::fmt::Display,
|
NodeData<F>: ::std::fmt::Display,
|
||||||
F::Key: ::std::fmt::Display,
|
F::Key: ::std::fmt::Display,
|
||||||
{
|
{
|
||||||
|
use super::Comparator;
|
||||||
|
use entity::SparseSet;
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
use super::Comparator;
|
|
||||||
use entity::SparseSet;
|
|
||||||
|
|
||||||
// The root node can't be an inner node with just a single sub-tree. It should have been
|
// The root node can't be an inner node with just a single sub-tree. It should have been
|
||||||
// pruned.
|
// pruned.
|
||||||
@@ -105,8 +106,8 @@ impl<F: Forest> NodePool<F> {
|
|||||||
);
|
);
|
||||||
let mut lower = lkey;
|
let mut lower = lkey;
|
||||||
|
|
||||||
match &self[node] {
|
match self[node] {
|
||||||
&NodeData::Inner { size, keys, tree } => {
|
NodeData::Inner { size, keys, tree } => {
|
||||||
let size = size as usize;
|
let size = size as usize;
|
||||||
let capacity = tree.len();
|
let capacity = tree.len();
|
||||||
let keys = &keys[0..size];
|
let keys = &keys[0..size];
|
||||||
@@ -148,7 +149,7 @@ impl<F: Forest> NodePool<F> {
|
|||||||
lower = upper;
|
lower = upper;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&NodeData::Leaf { size, keys, .. } => {
|
NodeData::Leaf { size, keys, .. } => {
|
||||||
let size = size as usize;
|
let size = size as usize;
|
||||||
let capacity = keys.borrow().len();
|
let capacity = keys.borrow().len();
|
||||||
let keys = &keys.borrow()[0..size];
|
let keys = &keys.borrow()[0..size];
|
||||||
@@ -191,7 +192,7 @@ impl<F: Forest> NodePool<F> {
|
|||||||
lower = upper;
|
lower = upper;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&NodeData::Free { .. } => panic!("Free {} reached", node),
|
NodeData::Free { .. } => panic!("Free {} reached", node),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
//! Forest of sets.
|
//! Forest of sets.
|
||||||
|
|
||||||
|
use super::{Comparator, Forest, Node, NodeData, NodePool, Path, SetValue, INNER_SIZE};
|
||||||
use packed_option::PackedOption;
|
use packed_option::PackedOption;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use super::{INNER_SIZE, Comparator, Forest, NodePool, Node, NodeData, Path, SetValue};
|
|
||||||
|
|
||||||
/// Tag type defining forest types for a set.
|
/// Tag type defining forest types for a set.
|
||||||
struct SetTypes<K, C>(PhantomData<(K, C)>);
|
struct SetTypes<K, C>(PhantomData<(K, C)>);
|
||||||
@@ -351,10 +351,10 @@ where
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
use super::super::NodeData;
|
||||||
|
use super::*;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
use super::*;
|
|
||||||
use super::super::NodeData;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn node_size() {
|
fn node_size() {
|
||||||
|
|||||||
@@ -14,13 +14,13 @@
|
|||||||
//! relocations to a `RelocSink` trait object. Relocations are less frequent than the
|
//! relocations to a `RelocSink` trait object. Relocations are less frequent than the
|
||||||
//! `CodeSink::put*` methods, so the performance impact of the virtual callbacks is less severe.
|
//! `CodeSink::put*` methods, so the performance impact of the virtual callbacks is less severe.
|
||||||
|
|
||||||
use ir::{ExternalName, JumpTable};
|
use super::{Addend, CodeOffset, CodeSink, Reloc};
|
||||||
use super::{CodeSink, CodeOffset, Reloc, Addend};
|
use ir::{ExternalName, JumpTable, SourceLoc, TrapCode};
|
||||||
use std::ptr::write_unaligned;
|
use std::ptr::write_unaligned;
|
||||||
|
|
||||||
/// A `CodeSink` that writes binary machine code directly into memory.
|
/// A `CodeSink` that writes binary machine code directly into memory.
|
||||||
///
|
///
|
||||||
/// A `MemoryCodeSink` object should be used when emitting a Cretonne IL function into executable
|
/// A `MemoryCodeSink` object should be used when emitting a Cretonne IR function into executable
|
||||||
/// memory. It writes machine code directly to a raw pointer without any bounds checking, so make
|
/// memory. It writes machine code directly to a raw pointer without any bounds checking, so make
|
||||||
/// sure to allocate enough memory for the whole function. The number of bytes required is returned
|
/// sure to allocate enough memory for the whole function. The number of bytes required is returned
|
||||||
/// by the `Context::compile()` function.
|
/// by the `Context::compile()` function.
|
||||||
@@ -33,15 +33,21 @@ pub struct MemoryCodeSink<'a> {
|
|||||||
data: *mut u8,
|
data: *mut u8,
|
||||||
offset: isize,
|
offset: isize,
|
||||||
relocs: &'a mut RelocSink,
|
relocs: &'a mut RelocSink,
|
||||||
|
traps: &'a mut TrapSink,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> MemoryCodeSink<'a> {
|
impl<'a> MemoryCodeSink<'a> {
|
||||||
/// Create a new memory code sink that writes a function to the memory pointed to by `data`.
|
/// Create a new memory code sink that writes a function to the memory pointed to by `data`.
|
||||||
pub fn new(data: *mut u8, relocs: &mut RelocSink) -> MemoryCodeSink {
|
pub fn new<'sink>(
|
||||||
|
data: *mut u8,
|
||||||
|
relocs: &'sink mut RelocSink,
|
||||||
|
traps: &'sink mut TrapSink,
|
||||||
|
) -> MemoryCodeSink<'sink> {
|
||||||
MemoryCodeSink {
|
MemoryCodeSink {
|
||||||
data,
|
data,
|
||||||
offset: 0,
|
offset: 0,
|
||||||
relocs,
|
relocs,
|
||||||
|
traps,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -58,6 +64,12 @@ pub trait RelocSink {
|
|||||||
fn reloc_jt(&mut self, CodeOffset, Reloc, JumpTable);
|
fn reloc_jt(&mut self, CodeOffset, Reloc, JumpTable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A trait for receiving trap codes and offsets.
|
||||||
|
pub trait TrapSink {
|
||||||
|
/// Add trap information for a specific offset.
|
||||||
|
fn trap(&mut self, CodeOffset, SourceLoc, TrapCode);
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> CodeSink for MemoryCodeSink<'a> {
|
impl<'a> CodeSink for MemoryCodeSink<'a> {
|
||||||
fn offset(&self) -> CodeOffset {
|
fn offset(&self) -> CodeOffset {
|
||||||
self.offset as CodeOffset
|
self.offset as CodeOffset
|
||||||
@@ -105,4 +117,9 @@ impl<'a> CodeSink for MemoryCodeSink<'a> {
|
|||||||
let ofs = self.offset();
|
let ofs = self.offset();
|
||||||
self.relocs.reloc_jt(ofs, rel, jt);
|
self.relocs.reloc_jt(ofs, rel, jt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn trap(&mut self, code: TrapCode, srcloc: SourceLoc) {
|
||||||
|
let ofs = self.offset();
|
||||||
|
self.traps.trap(ofs, srcloc, code);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user